原题链接: https://leetcode.com/problems/subarray-sum-equals-k/
1.题目描述
求解:所有整数加起来和等于k的子数组有多少个?
Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k.
Example 1:
Input:nums = [1,1,1], k = 2
Output: 2
Note:
The length of the array is in range [1, 20,000].
The range of numbers in the array is [-1000, 1000] and the range of the integer k is [-1e7, 1e7].
2. 解题思路
2.1 暴力搜索
速度较慢。使用两个循环,从头到尾遍历数组,从某个元素开始,一直向后加,如果遇到和等于k的,总数就+1。
这里有一点需要注意,必须加到最后一个元素,因为有可能遇到这样的情况:
加入k=6,数组是{1,2,3,-5,5},假设搜索时从1开始向后加,加到3时,和等于6,这时总数+1,但是不能跳出循环,要继续加到最后一个元素,否则就会漏掉1+2+3+(-5)+5=6 这个也等于6的和。
class Solution {
public int subarraySum(int[] nums, int k) {
int res =0;
int length = nums.length;
for(int i=0;i<length;i++){
int temp=nums[i];
if(temp==k){ res ++; }
for(int j=i+1;j<length;j++){
temp=temp+nums[j];
if(temp ==k) {res ++;}
}
}
return res;
}
}
2.2 借助HashMap
这个题还有另外一个思路。可以让时间复杂度达到O(n)。
如果想知道从nums[ i ] +nums[ i+1 ] + ···+ nums[ j ]的和,那么就可以用(nums[ 0 ] +nums[ 1 ] + ···+ nums[ j ] ) - (nums[ 0 ] +nums[ 1 ] + ···+ nums[ i-1 ])来求得。
为了说的更清楚一些,我们举个例子,假设有这样一个数组nums,共有9个元素:
如果要计算nums[2]+nums[3]+nums[4],也就是7-5+0的值,可以采用这样的做法:
首先,计算nums[0] +···+nums[4]的和,也就是(3+6+7-5+0);
然后,计算nums[0]+···+nums[1]的和,也就是(3+6);
最后,前者减去后者。
也即(3+6+7-5+0)- (3+6) = 7-5+0。
我现在把这个例子中,从第一个元素开始加,加到第i个元素时的和都计算出来。
于是这个问题就转化为,求sum值中,相差为k的数字有多少对?
当然,不能忘记另外一种情况:nums[0]开始加的和直接等于k。
比如k=9时,那么nums[1]+nums[2]就满足条件了,因此需要在所有sum值前面再补一个0,这样就能找到相差为9的数字对了。
我们接下来将所有的sum值及出现的次数放在一个HashMap里:
具体的过程如下所示:比如k=6,Count是结果,初值为0
0:HashMap里面只有0,出现次数为1
1:sum = 3,HashMap没有3,于是添加进去,出现的次数也为1
2: sum=9,而k=6,sum-k=3,这个3在HashMap里面有,于是Count加上3的次数1,Count = 0+1=1;并且要把{9,1}放入HashMap
3:sum=16,HashMap没有16,放入
4: sum = 11,HashMap没有11,放入
5: sum又=11,为HashMap中11出现的次数+1
6:sum 又= 9,而k=6,sum-k=3,这个3在HashMap里面有,于是Count加上3的次数1,Count=1+1 =2,现在sum中有两个9,一个3出现,也就是有两对9-3=6的结果满足k=6的条件了。
然后把9在HashMap中的次数+1
7:sum又=11,为HashMap中11出现的次数+1
8:sum=15 ,15-k=15-6=9,在HashMap中9出现了2次,意味着有1个15,2个9,可以找到2对15-9=6,所以Count+2,Count= 2+2=4;
然后把{15,1}放入HashMap
9:sum=21,sum-k=21-6=15,因此Count需要加上15在HashMap中的次数,Count=4+1 =5;
然后把{21,1}放入HashMap
至此,一个完整的HashMap构造完了,同时也计算出来了满足k=6的结果Count=5
实现代码
public class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer,Integer> h = new HashMap<>();
int Count=0;
int length = nums.length;
int sum =0;
h.put(0,1);
for(int i =0;i<length ;i++) {
sum+=nums[i];
if(h.containsKey(sum-k)) {
int temp = h.get(sum-k);
Count += temp;
}
if( h.containsKey(sum) ) {
int temp2 = h.get(sum);
h.put(sum, temp2+1);
}
else {
h.put(sum,1);
}
}
return Count;
}
}
3. 参考材料
https://leetcode.com/problems/subarray-sum-equals-k/solution/
4. n-Sum专题相关题目
1. Two Sum
15. 3Sum
16. 3Sum Closest
18. 4Sum
167. Two Sum II - Input array is sorted
560. Subarray Sum Equals K
653. Two Sum IV - Input is a BST