给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :
数组的长度为 [1, 20,000]。
数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k
一开始想到的是滑动窗口的思路
public int subarraySum(int[] nums, int k) {
int i,j = 0,sum = 0;
int count = 0;
for(i = 0; i < nums.length; i++){
sum += nums[i];
while(j < nums.length && sum >= k){
if(sum == k)
count++;
sum -= nums[j];
}
}
return count;
}
但是最后提交代码的时候会发现有错误,为什么呢?错误提示给出了一个测试用例[-1,-1,-1],k = -2,如果按照上面的例子来做的话,那么返回的是0,但是应该返回的是1.所以利用滑动窗口来实现的时候,必须要保证所有的数字都是正数才可以的,否则就会发生错误,因为题目中有说到元素的范围,所以会存在负数。
暴力解决:
class Solution {
public int subarraySum(int[] nums, int k) {
int i,j,sum = 0;
int count = 0;
for(i = 0; i < nums.length; i++){
sum = nums[i];
if(sum == k)
count++;
/*
考虑到元素是负数的情况,所以尽管当前元素等于了k,依旧需要考虑从这个元素开始的连续子数
组的和是否为k
*/
for(j = i + 1; j < nums.length; j++){
sum += nums[j];
if(sum == k)
count++;
}
}
return count;
}
}
运行结果:
方法二:前缀和 + 哈希表
前缀和pre[ i ] 表示的是以下标为0开始,下标 i 结尾的连续子数组和。
所以假设 [ j , i ]是和为k的连续子数组的和,那么就会存在这样的关系:pre[ i ] - pre[ j - 1] = k。基于此,如果 i 结尾的连续子数组的和为k,主要取决于前缀和pre[ j - 1 ]有多少种情况,pre[ j - 1]有多少种情况,以 i 结尾的连续子数组和为 k 就有多少种情况。
所以我们就利用哈希表,其中对应的键是表示从0开始,i 结尾的连续子数组的和pre,对应的值表示pre存在的可能情况。
则有对应的代码:
class Solution {
public int subarraySum(int[] nums, int k) {
HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
int i,pre = 0;//pre表示以从0开始,到下标为i结尾的连续子数组的和
boolean flag;
int count = 0;
/*
map.put(0,1)这一步是必要的,因为可能存在0开始,下标i结尾的连续和刚好是k
例如例子[1,1,1],k = 2,那么如果没有这一步的话,最后返回的结果是1,但是实际应该
是2,原因就是因为第二个1出现了错误,第二个1的时候,pre = 2,由于没有进行map.put(0,1)
这一步,从而导致flag为false,所以就少了这一种情况,从而导致错误
*/
map.put(0,1);
for(i = 0; i < nums.length; i++){
pre += nums[i];//获取以i结尾的连续和
/*
从0开始,i结尾的连续和,如果假设[j,i]是连续和为k的子数组,那么pre[i] - pre[j - 1] = k
所以再直到以i结尾连续和子数组之和,要求连续和为k的
*/
flag = map.containsKey(pre - k);
if(flag){
//以i结尾的连续和为k的子数组的个数主要取决于连续和为pre - k的连续子数组的所有可能
count += map.get(pre - k);
}
//将当前i结尾的连续子数组的和压入到哈希表中,如果之前已经存在了,那么就原来基础上加1
if(map.containsKey(pre))
map.put(pre,map.get(pre) + 1);
else
map.put(pre,1);
}
return count;
}
}
运行结果: