525. 连续数组

思路:
这道题,我一开始想用栈存0,然后遇到1就取出来一个0,同时计数,但是这样就有个问题,有可能中间有多个0,后面有多个1只能匹配中间的一部分0,导致得到的子数组不是连续的。
然后就没办法了...
去看题解,当我把0改为-1,那就可以通过前缀和来实现了。这里多提一下前缀和的简单定义吧,前缀和本质是「容斥原理」,只要存在逆运算帮助实现抵消重复计算的部分,就算作前缀和。
当我们把0改为-1,那么我们就能知道一对01,结果就为0,那么我们就是寻找[最长的和为0的子数组],那么我们求数组的前缀和,发现0即可知道前面出现了至少一对01。
那么我们通过hash表的键来存储下标i的前缀和,值存下标i。实现的步骤为,如果该前缀和被存过了,那么再次遇到说明找到了一段01个数相同的连续子数组,一个数组中会有多个,每次取最大的即可。
在找01对时,前缀和会升升降降,不管此时前缀和为多少,例如为-1,后面可能遇到多个0,降到-5,又遇到多个1升到-1,然后此时判断hash表存过-1,那么这段就很明显01个数是相同的,否则不可能在之后还会遇到相同的键。
我这里有个疑问,为什么他们要设置mp[0]=0或者-1呢,我不用也能AC啊。。。我上道题也解释了初始化为mp[0]=-1,是可以理解就是补了下标是从0开始,而长度应该要下标+1,这个-1就是补了这个1,有的设为-1是方法不同,因为第一个元素前缀和必为0,所以不用,如果不额外使用数组存前缀和就需要补这个1了。那么设为0的就没必要了。不知道这样理解是否正确

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        int n = nums.size();
        vector<int> presum(n+1,0);
        for(int i=1;i<n+1;++i){
            presum[i] = presum[i-1]+(nums[i-1]==1?1:-1);
        }
        unordered_map<int,int> mp;
        int res=0;
        for(int i=0;i<n+1;++i){
            if(mp.count(presum[i])) res = max(res,i-mp[presum[i]]);
            else {
                mp[presum[i]] = i;
            }
        }
        return res;
    }
};
posted @ 2021-06-03 20:39  Mrsdwang  阅读(34)  评论(0编辑  收藏  举报