031 连续数组
题目描述: 给定一个二进制数组 nums,找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
解法一:暴力解法
直接枚举所有子数组并统计 0 和 1 的数量,时间复杂度为 O(n^2),在数据量较大时容易超时,这里不再赘述。
解法二:前缀和在哈希表中
这道题的核心在于转化。如果我们将数组中的 0 记为 -1,1 记为 1,那么问题就转化为:寻找一段区间,这段区间的元素之和等于 0。
设 sum[i] 表示从索引 0 到 i 的前缀和。如果存在两个位置 i 和 j (j < i),使得 sum[i] == sum[j],那么区间 [j+1, i] 内的元素和必然为 0。因此,我们只需要记录每个前缀和第一次出现的位置。
具体实现时,不需要真的维护一个前缀和数组,只需遍历一遍,用哈希表存储 前缀和 -> 首次出现的下标。初始化时,将前缀和 0 映射到下标 -1,以处理从数组开头开始满足条件的情况。
C++ 实现
class Solution {
public:
int findMaxLength(vector<int>& nums) {
unordered_map<int, int> hash;
// 初始化:前缀和为 0 时,对应下标为 -1
hash[0] = -1;
int sum = 0, ret = 0;
for (int i = 0; i < nums.size(); ++i) {
// 0 视为 -1,1 视为 1
sum += (nums[i] == 0 ? -1 : 1);
if (hash.count(sum)) {
// 如果当前前缀和之前出现过,说明中间这段区间和为 0
ret = max(ret, i - hash[sum]);
} else {
// 只记录第一次出现的位置,保证长度最长
hash[sum] = i;
}
}
return ret;
}
};
时间复杂度:O(n),空间复杂度:O(n)。


