题目描述:
给你一个整数数组 nums 和一个整数 k ,请你统计并返回该数组中和为 k 的连续子数组的个数。
示例 1:
输入:nums = [1,1,1], k = 2
输出:2
示例 2:
输入:nums = [1,2,3], k = 3
输出:2
提示:
1 <= nums.length <= 2 * 10^4
-1000 <= nums[i] <= 1000
-10^7 <= k <= 10^7
错误思路(可不看) 第一眼看到有点懵,没做过类似的,初次觉得用滑动窗口思想,但是k和nums中均有负数所以不符合.后面想到用暴力,但是暴力可以达到O(n^3)肯定超时,于是想着在暴力基础上优化,借dp思想想到优化思路,用dp[i][j]表示下标i到j-1(包括i和j-1下标)的元素和 这样dp[i][j]=dp[0][j]-dp[0][i]
但是还是超时了,时间也有O(n^2),错误代码:
int subarraySum(vector<int>& nums, int k) {
int n = nums.size(),sum=0;
vector<vector<int>>dp(n, vector<int>(n+1));//dp[i][j]表示下标i到j-1(包括i和j-1下标)的元素和 这样dp[i][j]=dp[0][j]-dp[0][i]
dp[0][1] = nums[0];
if (dp[0][1] == k) sum++;
for (int i = 2; i <= n; i++) {
dp[0][i] = dp[0][i - 1] + nums[i - 1];
if (dp[0][i] == k) sum++;
}
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
dp[i][j] = dp[0][j] - dp[0][i];
if (dp[i][j] == k) sum++;
}
}
return sum;
}
其实完全不用dp数组,直接二重循环i从0~n-1 j从i->0遍历,每次遍历用上次循环的和加上nums[j]统计个数也能达到O(n^2),空间O(1)。
正确思路:
用前缀和pre[i]表示0~i的元素和 则以i为结尾的元素和:pre[i]-pre[j-1]表示j~i的元素和 即nums[j…i]
则其中符合要求的元素应该是:pre[i]-pre[j-1]=k 所以pre[j-1]=pre[i]-k
所以对于以i为结尾的元素 我们只要数一数pre[0]~pre[i-1]里面有几个值为pre[i]-k,再判断pre[i]是否为k 就可以得出以i为结尾的元素有多少个符合要求。
ps: 上面的这些判断的边界情况我再具体解释一下:
判断pre[i-1]是否等于pre[i]-k,是判断以nums[i]自己是否等于k的情况,即一个元素组成的子数组;
判断pre[0]是否等于pre[i]-k,是判断nums[1…i]是否等于k的情况;
判断pre[i]是否等于k,是判断nums[0…i]是否等于k的情况,这个条件的判断最容易忽略。
那么我们可以从0~n-1遍历nums数组, 然后每次遍历到i 就通过pre[i-1]+nums[i]=pre[i]计算pre[i],然后将所有的前缀和统统放入map,key保存pre[i],value则保存这个pre[i]的出现次数。
这样我们可以以O(1)的时间来获得pre[0]~pre[i-1]里面有几个值为k 但是这里问题又来了 我们的map里怎么保证里面所有的key都是pre[0~i-1]呢?
要不然我们得到pre[i+5]也是=pre[i]-k,但是我们要求的是以i为结尾,这个显然不是
这个问题很好解决,我们存入pre[i]的前一步就计算以i为结尾的元素有多少个符合要求,这样map里就不会有大于i的键值,即所有map的key都是0~i-1
优化:因为计算pre[i]只用到pre[i-1] 所以pre可以不用数组存储 用一个单位就行了
正确代码:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int>mymap;//因为我们只需存取,不用排序所以用unordered更快
int n = nums.size(),pre=nums[0],sum=0;//sum存返回值,,即符合条件个数
mymap[pre] = 1;
if (nums[0] == k) sum++;
for (int i = 1; i < n; i++) {
pre += nums[i];
if (pre == k) sum++;
sum += mymap[pre - k];
mymap[pre]++;
}
return sum;
}
空间和时间O(n)即可解决问题