题意
给一个由非负正数组成的数组和一个数k,要求在数组中找一段长度≥2的序列使其和是k的整数倍。
思路
算法1
O(n2)时间,O(n)空间
维护数组的前缀和s,对于当前
注意k=0的情况。
算法2
如果要求和刚好为k的话,我们对于当前和si,只需要知道之前是否存在sj=si−k即可,于是可以用unordered_map
O(1)的去查找。
既然是k的整数倍,我们可以利用%的性质:
x%p=a等价于x=pn+a(1)
y%p=a等价于y=pm+a(2)
(2)和(1)相减既有:y−x=p(m−n),即y−x是p的整数倍。
所以,我们不维护前缀和而是前缀和%k之后的值x,并且用map保存每个x出现的最早位置,当再次出现x的时候,并且长度大于1,那么就是我们的结果。
代码
algorithm 1
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
vector<int> sum(nums.size(), 0);
if (nums.size()) {
for (int i = 0; i < nums.size(); i++) sum[i] = (i ? sum[i - 1] : 0) + nums[i];
for (int i = 0; i < nums.size(); i++) {
if (k == 0) {
if (i && sum[i] == 0) return true;
} else {
if (sum[i] % k == 0 && i) return true;
}
for (int j = 0; j < i - 1; j++) {
int x = sum[i] - sum[j];
if (k == 0) {
if (x == 0) return true;
} else {
if (x % k == 0) return true;
}
}
}
}
return false;
}
};
algorithm 2
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
unordered_map<int, int> pos;
if (nums.size()) {
int sum = 0; pos[0] = -1;
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
if (k) sum %= k;
if (pos.count(sum)) {
int x = pos[sum];
if (i - x > 1) return true;
} else {
pos[sum] = i;
}
}
}
return false;
}
};