题目链接:LeeCode560和为k的子数组
题目描述:
这道题最开始想用滑窗做,但是后来考虑数组里面是有负数的,方向是出错的,首先考虑最笨的放法就是遍历一遍确定左边界,然后向后计算是否有结果等于k的子数组。时间复杂度O(n*n),然后考虑前缀和,算出所有的前缀和例如1 1 1 1 1 k=3,前缀和为1 2 3 4 5 结果等于3的子数组就是 4-1,5-2,3-0三种情况。得出代码:
class Solution {
public static int subarraySum(int[] nums, int k) {
int[] presum=new int[nums.length];
presum[0]=nums[0];
int ans=0;
//求出前缀和
for (int i = 1; i < presum.length; i++) {
presum[i]=presum[i-1]+nums[i];
}
//确定左右边界计算所有能成功的前缀和组合
for (int i = 0; i < nums.length; i++) {
for (int j = i; j < nums.length; j++) {
if(presum[j]-presum[i]+nums[i]==k)ans++;
}
}
return ans;
}
}
之后考虑优化,可以用hashmap存下之前出现过前缀的次数,每次找到一个前缀都判断是否有与之配对的前缀以及个数,故而得出答案
class Solution {
public static int subarraySum(int[] nums, int k) {
int[] presum=new int[nums.length];
Map<Integer,Integer> map=new HashMap<>();
presum[0]=nums[0];
int ans=0;
//求出所有前缀和
for (int i = 1; i < presum.length; i++) {
presum[i]=presum[i-1]+nums[i];
}
//当nums里面有某个数等于k或者第一次算出k时加一
map.put(0,1);
for (int i = 0; i < presum.length; i++) {
if(map.containsKey(presum[i]-k)){
//有几个与之配对的前缀就加几
ans+=map.get(presum[i]-k);
}
//维护所有前缀
map.put(presum[i], map.getOrDefault(presum[i],0)+1);
}
return ans;
}
}