523. 连续的子数组和

思路:
想到了前缀和的方法,但还是没法避免用了两重循环,然后还是超时了。
看了题解也是前缀和,但是他的前缀和求的和我想的有不同,并且还用了hash表来优化。
这里主要问题是我没能想到同余定理,什么是同余定理呢。
举个例子: 23,2,4,6,7.k=6我们知道2,4能够满足条件。那么2,4的求解为前缀和29-23,即6和2的前缀和相减的得到2+4的结果。
那么对于23和29,有23%6=29%6=5.为什么?我们知道23/6=3,29/6=4,那么有29-23=(46+5)-(36+5),所以同于定理保证了x-y=nk时,x和y变为(ab+l)形式时,x-y能把l消除掉才能使相减的结果为k的n倍。总结为,如果x、y满足x-y为k的n倍的话,那么x、y余k的结果相同。
如果想到这点,那就容易想到了,我只需要遍历一次,每次把前缀和模k的结果存入一个数据结构,我们每次存入之前都要判断数据结构中是否存入了前缀和模k结果相同的内容,已经有了我们就找到了满足k倍数的子数组。所以这个数据结构需要有高效的查找效率,所以我们采用hash表。
hash表的键为模k的结果,值为该数的下标。
我们需要先让模k=0的结果设为-1,这是一个边界条件,如果某个前缀和就为k的倍数,那么我们就算发现了一个满足条件的结果,而这个长度就等于idx-(-1),例如1,5,7.k=6,那么我们前缀和6的时候就满足条件,5的下标为1,那么1-(-1)=2这样才满足1,5的长度2。

代码:

class Solution {
public:
    bool checkSubarraySum(vector<int>& nums, int k) {
        int n = nums.size();
        if(n<2) return false;
        unordered_map<int,int> mp;
        mp[0]=-1;
        int presum=0;
        for(int i=0;i<n;++i){
            presum = (presum + nums[i])%k;
            if(mp.count(presum)){
                if(i-mp[presum]>=2) return true;
            }
            else mp[presum]=i;
        }
        return false;
    }
};
posted @ 2021-06-02 18:08  Mrsdwang  阅读(29)  评论(0编辑  收藏  举报