1. 问题背景与核心思路
这道题目要求我们找出数组中所有和为k的连续子数组的个数。乍一看似乎需要枚举所有可能的子数组,但这样的暴力解法时间复杂度会达到O(n²),对于大规模数据显然不够高效。
这里引入前缀和的概念:前缀和数组的第i项表示原数组前i项的和。通过预处理得到前缀和数组后,任意子数组的和都可以通过两个前缀和相减得到。例如,子数组nums[i..j]的和等于prefix[j+1] - prefix[i]。
但仅仅使用前缀和数组仍然需要双重循环。这时候哈希表就派上用场了——我们可以用哈希表记录每个前缀和出现的次数。遍历时,当前前缀和减去k的值如果在哈希表中存在,说明找到了满足条件的子数组。这种方法将时间复杂度优化到了O(n)。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 前缀和与哈希表的精妙配合
2.1 前缀和数组的构建
前缀和数组的构建非常简单:
code复制prefix[0] = 0
prefix[i] = prefix[i-1] + nums[i-1] (i > 0)
这样设计的好处是:
- 统一了边界条件的处理
- 空子数组的和为0,对应prefix[0]
- 子数组nums[0..j]的和直接就是prefix[j+1]
2.2 哈希表的实时更新
我们不需要显式地构建整个前缀和数组,而是可以在遍历时实时计算当前前缀和,并用哈希表记录每个前缀和出现的次数。具体步骤:
- 初始化哈希表hash_map,记录prefix_sum -> count
- 初始化prefix_sum = 0,count = 0
- 遍历数组:
- 更新当前prefix_sum += nums[i]
- 检查hash_map中是否存在(prefix_sum - k)
- 更新count
- 将当前prefix_sum存入hash_map
这种实时更新的方式节省了空间复杂度,从O(n)降到了O(1)。
3. 实现细节与边界条件
3.1 代码实现(C++示例)
cpp复制int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> prefix_map;
prefix_map[0] = 1; // 初始前缀和为0出现1次
