523. 连续的子数组和 , 前缀和、 hash
给定一个包含 非负数 的数组和一个目标 整数 k ,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,且总和为 k 的倍数,即总和为 n * k ,其中 n 也是一个整数。
7 3 6 6 6 6 6 6: 6
10 16 22 4 4 4
用数学分析:
x1%6 = t; x2%6 = t; 可得出:(x1-x2)%6 = 0;
只需要找出俩个余数相等的索引,并且间隔长度超2即可。
存入map: {key:sum % k, value:i}
考虑情况:k若为0
Hash写法 java:
import java.util.HashMap;
import java.util.Map;
public class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
int sum = 0;
// key:区间 [0..i] 里所有元素的和 % k
// value:下标 i
Map<Integer, Integer> map = new HashMap<>();
// 理解初始化的意义
map.put(0, -1);
int len = nums.length;
for (int i = 0; i < len; i++) {
sum += nums[i];
if (k != 0) {
sum = sum % k;
}
//其他参考 int key = k == 0 ? preSum : preSum % k;map.containsKey(key)
if (map.containsKey(sum)) {
if (i - map.get(sum) > 1) {
return true;
}
} else {
map.put(sum, i);
}
}
return false;
}
}
复杂度分析
- 时间复杂度:O(N)O(N),仅需要遍历输入数组一遍;
- 空间复杂度:O(min(n,k))O(min(n,k))。哈希表最多包含 min(n,k)min(n,k) 个不同的元素。
前缀和写法 java:
public class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
int len = nums.length;
int[] preSum = new int[len + 1];
preSum[0] = 0;
for(int i = 0; i < len; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
for(int left = 0; left < len - 1; left++) {
for(int right = left + 1; right < len; right++) {
int temp = preSum[right + 1] - preSum[left];
if (temp == k || (k != 0 && temp % k == 0)) {
return true;
}
}
}
return false;
}
}