力扣560. 和为 K 的子数组
Posted weixin_43739821
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了力扣560. 和为 K 的子数组相关的知识,希望对你有一定的参考价值。
题目描述:
给你一个整数数组 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]计算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)即可解决问题
以上是关于力扣560. 和为 K 的子数组的主要内容,如果未能解决你的问题,请参考以下文章