我正在尝试解决LeetCode.com上的问题:
给定一个非负数列表和一个目标整数k,写一个函数来检查该数组是否有一个大小至少为2的连续子数组,总和达到k的倍数,即总和为n * k其中n也是整数。例如,如果
[23, 2, 4, 6, 7]
,k=6
,则输出应为True
,因为[2, 4]
是大小为2的连续子数组,总计最多为6。
我想了解以下solution:
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
int n = nums.size(), sum = 0, pre = 0;
unordered_set<int> modk;
for (int i = 0; i < n; ++i) {
sum += nums[i];
int mod = k == 0 ? sum : sum % k;
if (modk.count(mod)) return true;
modk.insert(pre);
pre = mod;
}
return false;
}
};
我了解到我们正在尝试将0, (a/k), (a+b)/k, (a+b+c)/k
等存储到hashSet(k
!= 0
)中,并且我们在 next << / em>迭代,因为我们希望子阵列大小至少为2
。
但是,这是如何保证我们得到一个元素总和为k
的子数组?什么数学属性保证了这一点?
答案 0 :(得分:3)
集合modk
逐渐填充从数组开始处开始的连续子数组的所有和(被视为模k)。
关键的观察是:
a-b = n * k表示某些自然n iff
a-b≡0mod k iff
a≡bmod k
所以如果一个连续的子数组nums [i_0] ... nums [i_1],总和最多为0模k,那么两个子数组nums [0] .. nums [i_0]和nums [i_0 + 1 ] .. nums [i_1]有相同的总和模数k。
因此,如果从数组开头开始的两个不同的子数组具有相同的总和,则模数为k就足够了。
幸运的是,只有k个这样的值,所以你只需要使用一组大小为k。
一些挑剔:
答案 1 :(得分:0)
(a + b)%k =(a%k + b%k)%k
(23 + 2)%6 = 1
((23%6)+(2%6))%6 =(5 + 2)%6 = 1
modk存储您迭代计算的所有模块。如果在迭代中我得到一个在i-m处计算的重复模块,这意味着你添加了m个元素的子序列,其中和是k的倍数
i=0 nums[0] = 23 sum = 23 sum%6 = 5 modk = [5]
i=1 nums[1] = 2 sum = 25 sum%6 = 1 modk = [5, 1]
i=2 nums[2] = 4 sum = 29 sum%6 = 5 5 already exists in modk (4+2)%6 =0