问题描述
给定一个包含非负数的数组和一个目标整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。
示例 1:
输入: [23,2,4,6,7], k = 6
输出: True
解释: [2,4] 是一个大小为 2 的子数组,并且和为 6。
解题报告
根据同余定理:(a-b)%k==0
意味着 a%k==b%k
。有了这个定理,我们不妨从 前缀和 的角度来解决这个问题,子数组和为k的倍数,意味着 preSum[j]%k==preSum[i]%k
。由于并未给出 k 的范围,采用 map 来存储前缀和对 k 的余数。
本 题 中 的 数 组 是 非 负 的 \color{red}本题中的数组是非负的 本题中的数组是非负的
Update【2020年7月31日】:
关于为什么初始化 map[0]=-1
。当数组中最前面两个元素之和是 k
的倍数时,nums[0]-nums[1]%k==0
,此时 1-map[0]
理应等于 2
,所以初始化 map[0]=-1
实现代码
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
int sum=0;
unordered_map<int,int> map;
map.insert({0,-1});
for(int i=0;i<nums.size();i++){
sum+=nums[i];
if(k!=0)
sum=sum%k;
if(map.count(sum)){
if(i-map[sum]>1)
return true;
}
else
map.insert({sum,i});
}
return false;
}
};
参考资料
[1] 523. 连续的子数组和
[2] 题解区:官方答案