
【题目】:560. 和为 K 的子数组
方法1. 前缀和
class Solution { public: int subarraySum(vector<int>& nums, int k) { int res = 0; int n = nums.size(); vector<int> preSum(n + 1, 0); for(int i = 0; i < n; ++i) { preSum[i + 1] = preSum[i] + nums[i]; } for(int i = 0; i < n; ++i) { for(int j = i + 1; j <= n; ++j) { if(preSum[j] - preSum[i] == k) { ++res; } } } return res; } };
|
- 时间复杂度: O(n^2)
- 空间复杂度: O(n)
使用preSum数组来存储nums的前缀和,preSum[i] = nums[0] + nums[1] + … + nums[i - 1],这里一定要注意,存储的时候必须要从preSum[1]开始存,因为后边计算前缀和的时候,利用的是preSum[j] - preSum[i],得从preSum[1]开始存相减的时候才能不丢失num[i]的值。
方法2. 前缀和 + 哈希表
class Solution { public: int subarraySum(vector<int>& nums, int k) { int res = 0; unordered_map<int, int> preSumCnt; preSumCnt[0] = 1; int cur = 0; for(int i = 0; i < nums.size(); ++i) { cur += nums[i]; if(preSumCnt.find(cur - k) != preSumCnt.end()) { res += preSumCnt[cur - k]; } preSumCnt[cur]++; } return res; } };
|
使用preSumCnt的map计算前缀和为key的个数有value个。
对于下标为0之前的元素,前缀和为0,个数有1个,这个需要赋初值,后边相加的时候都需要以这个开始。
在遍历的时候,如果找到一个前缀和为cur - k时,说明从之前的某个位置到当前位置的子数组和为k。如果遍历到i时,前缀和为cur,而题目要求找到和为k的子数组。如果存在一个位置j(j < i),其前缀和为cur - k,那么从位置j到位置i的子数组和为k。
