LeetCode 523. 连续的子数组和
题目链接
思路分析
这个题我第一次做的时候只会暴力查,外层循环i
遍历整个数组,内层循环遍历[i, nums.length - 1]
,内层循环计算当前连续数组的和,如果遇到sum == k
或者k != 0 && sum % k == 0
的情况,就返回true
。当外层循环也遍历结束后,我们应该返回false
。
这样做的时间复杂度是O(n^2), 空间复杂度是O(1)。
代码实现
class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
for(int i = 0; i < nums.length; i++){
int sum = nums[i];
for(int j = i+1; j < nums.length; j++){
sum += nums[j];
if(sum == k || (k != 0 && sum % k == 0)){
return true;
}
}
}
return false;
}
}
后记
在做完之后,我看到了用HashMap
做的O(n)时间复杂度的做法,说实话真的NB,但是第一次做肯定是想不到这种思路的- -
利用同余的思想,如果两个余数相等,代表这两个余数之间的数组和是K
的倍数,但是因为要求数组长度必须大于等于2
,所以还得判断其距离差。
HashMap
的key
用于存放余数,value
用于存放余数出现的位置。
不得不说这个做法是真的巧妙~
O(n)官方实现
class Solution {
public boolean checkSubarraySum(int[] nums, int k){
int sum = 0;
Map<Integer, Integer> map = new HashMap<>(); // 键为 preSum % k, 值为索引,当然要特殊处理k == 0的情况
map.put(0, -1);
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
int temp = k == 0 ? sum : sum % k;
if(map.containsKey(temp)){ // 出现相同的键,如果子数组长度少于2, 不需要更新值。
if(i - map.get(temp) > 1) // 子数组要求长度至少为2。
return true;
continue;
}
map.put(temp, i);
}
return false;
}
}