/*
Sologala @github https://github.com/Sologala/LeetCode.git
[523]连续的子数组和
| continuous-subarray-sum
*/
给定一个包含非负数的数组和一个目标整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。
示例 1:
输入: [23,2,4,6,7], k = 6
输出: True
解释: [2,4] 是一个大小为 2 的子数组,并且和为 6。
示例 2:
输入: [23,2,6,4,7], k = 6
输出: True
解释: [23,2,6,4,7]是大小为 5 的子数组,并且和为 42。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/continuous-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
暴力枚举所有的部分和看是否能够整除 k
能过但是时间复杂度很高O(n^2)
首先我们来观察一下这一组数据 [23,2,4,6,7]
k = 6
//数组: [23 , 2 , 4 , 6 , 7]
//累加: [23 , 25, 29, 35,42]
//余数: [5 , 1 , 5 , 5 , 5]
通过以上的数据我们可以发现 数组的累加和对于K
的余数 当重复出现的时候就已经出现了 [2,4]
的和为 k = 6
. 因此我们可以使用hash
来统计当前这个余数出现的次数,一旦发现出现了2
次就可以 判断成立了 .
0
开始的累加和已经构成 k
的倍数有可能当前我们的累加和就正好是 `k` 的倍数,或者有累加和等于`0`,那么我们可以直接返回`true` 因为 **`0 * k = 0`**
k
== 1
如果 k == 1
的情况下,我们 可以直接返回 true
因为 无论累加和是什么我们都可以通过 1 * n
计算出来.
k
== 0
k == 0
k
是有可能等于 0
的,那么这个时候是不能直接使用我们最刚开始发现的规律,因为 k = 0
是不能作为分母求余数的.这个时候我们选取 K = 1000000007
使得每次求余之后的结果都保存在 int
的范围内.这样问题就变成了一个累加和的问题,虽然这里的求余已经意义不大,但是好在代码不用更改太多.
[0,1,0] , k = 0
这样的数据我们目前的代码是过不了的,当计算到最后一个 0
的时候他会觉得之前已经出现过了 余数1
,于是直接返回了 true
, 为了解决这个问题 ,我们需要使用 hash
存储是否出现 的时候存下当前的下标,如果我们判断已经出现过之后,还要追加判断是否距离超过1
,这样才能说明已经出现了.
k
为 负值 这个时候处理一下就行了
k = k< 0 ? - k : k ;
以上就是所有的坑点,提交了 15
次踩出来的 (捂头抹泪~~)
执行用时 :28 ms, 在所有 C++ 提交中击败了99.29%的用户
内存消耗 :11.4 MB, 在所有 C++ 提交中击败了46.10%的用户
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
unordered_map<int,int> m;
if(nums.size()<=1) return false;
k = (k < 0? -k : k);
if(k==1) return true;
k = (k == 0 ? 1000000007 : k);
int cur =0;
for(int i = 0;i<nums.size();++i){
cur = (cur + nums[i]);
if((cur== k||cur==0)&&i>0) return true;
int idx = m[cur%k];
if(idx)
{
if(i - idx + 1 > 1) return true;
}
else m[cur%k] = i + 1;//这里我存储的是 从1开始为了避免 0
}
return cur == 0;
}
};