[M前缀和] lc525. 连续数组(前缀和+知识理解+思维)

Posted Ypuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[M前缀和] lc525. 连续数组(前缀和+知识理解+思维)相关的知识,希望对你有一定的参考价值。

1. 题目来源

链接:525. 连续数组

2. 题目解析

前缀和变种,思维型题目。

在此 s[i] 定义为,前 i 个数中,1 的个数减去 0 的个数的差值。在此定义下,[j,i] 区间的 1 的个数减去 0 的个数的差值就是 s[i]-s[j-1]是满足前缀和的推导公式的,也可以看作是容斥原理。

那么针对 i 位置,以 i 位置为终点,j 为起点,若能构成答案,则必然有 s[i]-s[j-1]=0 即 1 的个数与 0 的个数相等,即 s[i]=s[j-1]

故相当于统计 i 位置之前是否存在与 s[i] 相等的位置即可。且在此需要求的是区间长度,故哈希表统计两个值 :s[j],j,首先在哈希表中 hs[0]=0,作为边界。

顺序枚举 i,如果哈希表中存在 s[i] 值相等的话,就是满足条件的答案区间,可以更新答案。如果不存在 s[i] 值相等的话,说明 s[i] 是第一次出现,对应的 i 位置也是第一次出现的最小下标,故更新 hs[s[i]] = i


知识理解:

注意前缀和需要深刻理解下标这个概念,[j, i] 区间 1 和 0 的差值是 s[i]-s[j-1]。再进一步,[i,i] 这个区间,其长度是 1,其 1 和 0 的差值是 s[i]-s[i-1]

我们在下标存储的时候是针对 s[i] 存的 i 下标,那么针对 s[i-1] 就存的是 i-1 这个下标。对应的 s[j-1] 存的就是 j-1 这个下标。

那么当我们找到和 s[i] 相等的值的时候,计算区间长度,按理说是左端点减右端点再 +1 的,但是针对前缀和这种特殊的问题来讲,若 s[i]=s[j] 其实是 [j+1,i] 区间是答案,故可以直接进行 i-j 就等价于 i-(j+1)+1 作为区间长度了。


时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( n ) O(n) O(n)


class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        int n = nums.size();
        unordered_map<int, int> hs;
        hs[0] = 0;
        int res = 0;
        for (int i = 1, one = 0, zero = 0; i <= n; i ++ ) {
            int x = nums[i - 1];
            if (x) one ++ ;
            else zero ++ ;
            
            int s = one - zero;
            if (hs.count(s)) res = max(res, i - hs[s]); // 前缀和求区间长度不需要 +1
            else hs[s] = i;		// 没有出现过,是最小下标
        }
        return res;
    }
};

以上是关于[M前缀和] lc525. 连续数组(前缀和+知识理解+思维)的主要内容,如果未能解决你的问题,请参考以下文章

525. 连续数组(前缀和+哈希)

[M前缀和] lc930. 和相同的二元子数组(滑动窗口+双指针+哈希优化)

[M前缀和] lc560. 和为K的子数组(经典好题+哈希优化)

LeetCode 525 连续数组[前缀和 哈希表] HERODING的LeetCode之路

[LeetCode] 525. 连续数组

LeetCode 0525. 连续数组:哈希表 + 前缀和