一.题目描述
525. 连续数组 - 力扣(LeetCode)
二.题目解析
让我们找到一个最长的数组,里面的0,1个数是相等的。
这道题依旧不能用滑动窗口解决,因为找到满足的之后,需要继续遍历。
我们可以对数组进行转换,让我们找0,1相等的数组,我们可以将0变为-1,此时问题就转变为求和为0的最长的子数组。
三.算法原理
前缀和+哈希表
经过转换,这道题就类似于求和为k的子数组了。只不过这道题需要求最长的。
我们先来分析一下满足要求的子数组与前缀和之前有什么关联:
首先满足要求的区间和为0,所以sum - x = 0。即sum = x。我们要求最长的和为0的子区间,那x区间,一定就最短且等于x。所以我们在遍历的过程中,要去寻找,前缀和等于sum的区间,且该区间还得是最短的。
接下来我们就用哈希表来存对应的前缀和x。但是key不再是前缀和出现的次数了,而是其下标。当我们知道了前缀和x的下标了,也知道i,那么所求区间的长度就等于i-dp[sum].
但是我们在遍历的过程中,可能有很多相等的sum,它们对应的下标不同,但是如果哈希表中已经有了sum,就没必要再插入了,因为后面插入的sum对应的下标更大,最终的结果就更小。
边界情况:如果此时i位置的前缀和sum刚好等于0呢?说明该区间就符合要求。此时怎么计算呢?因为最终结果ret = i - dp[sum].说明此时(0,i)这个区间满足要求,长度是i+1.而直接用公式i-mp[sum] = i.为了满足结果,所以dp[0] = -1.
时间复杂度:所有的运算都在一遍遍历的过程中完成,所以时间复杂度是O(n)
空间复杂度:空间复杂度的开销主要在于哈希表,而哈希表存储的是前缀和,所以最坏情况下,哈希表的大小为n,所以空间复杂度为O(n)
四.代码实现
// C++
class Solution
{
public:
int findMaxLength(vector<int>& nums)
{
// 前缀和及该区间的长度
unordered_map<int, int> mp;
mp[0] = -1;
int ret = 0,n = nums.size();
for(int i=0, sum=0; i<n; ++i)
{
sum += nums[i] == 0?-1:1;
if (mp.count(sum)) ret = max(ret,i-mp[sum]);
if(!mp.count(sum)) mp[sum] = i;
}
return ret;
}
};
# python
class Solution:
def findMaxLength(self, nums: List[int]) -> int:
mp = {0:-1}
sum,ret = 0,0
for i in range(0,len(nums)):
sum += -1 if nums[i] == 0 else 1
if sum in mp:
ret = max(ret,i-mp[sum])
if sum not in mp:
mp[sum] = i
return ret