连续的子数组的和
题目
给定一个包含 非负数 的数组和一个目标 整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,且总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。
思路
利用前缀和,首先遍历一遍数组,找到每个位置的前缀和保存到sum[i]中,sum[i]=nums[0]+…+nums[i]。
然后遍历前缀和数组,若有sum[i]-sum[j] = nums[j+1]+…+nums[i]等于目标值的倍数,则返回true,这种方法的复杂度是O(n^2)。
优化
使用mod运算和hashmap实现一次遍历:我们可以发现如果sum[i]%k == sum[j]%k,那么必然后sum[i]-sum[j]=n*k。所以我们每次将sum[i]%k的余数存入hashmap,在遍历过程中,如果存在冲突,那么必然有sum[i]%k==sum[j]%k(注意需要检查子数组长度)。
代码
class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
if(nums == null || nums.length < 2){
return false;
}
Map<Integer, Integer> map = new HashMap<> ();
map.put(0,-1); //不设置-1位置,[1,1] 2 这种用例无法通过
int sum = 0;
for(int i = 0; i < nums.length; i++){
sum += nums[i];
if(k!=0){
sum %= k;
}
if(map.containsKey(sum)){
if(i-map.get(sum) > 1){ //检查子数组长度
return true;
}
}else{
map.put(sum, i);
}
}
return false;
}
}