031 连续数组
题目链接:525. 连续数组
题目描述: 给定一个二进制数组 nums,找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
解法一:暴力解法
暴力解法是枚举所有可能的子数组,统计其中 0 和 1 的数量是否相等。这种方法的时间复杂度为 O(n^3) 或 O(n^2),在数据量较大时容易超时,因此不推荐。
解法二:前缀和 + 哈希表
这道题的关键在于转化思路。如果我们将数组中的 0 视为 -1,1 保持不变,那么问题就转化为:寻找最长的子数组,使得其元素之和为 0。
设 sum[i] 表示从索引 0 到 i 的前缀和。如果存在两个索引 j < i,使得 sum[j] == sum[i],那么区间 (j, i] 内的元素之和必然为 0。为了找到最长子数组,我们需要记录每个前缀和第一次出现的位置。
具体步骤如下:
- 初始化一个哈希表,用于存储前缀和及其首次出现的下标。初始状态存入
{0: -1},表示前缀和为 0 出现在索引 -1 处(虚拟边界)。 - 遍历数组,累加当前前缀和。将 0 视为 -1,1 视为 1。
- 检查当前前缀和是否已存在于哈希表中:
- 若存在,说明找到了一个和为 0 的区间,更新最大长度
max_len = max(max_len, i - hash[sum])。 - 若不存在,将当前前缀和及索引存入哈希表。
- 若存在,说明找到了一个和为 0 的区间,更新最大长度
- 遍历结束后返回最大长度。
注意:空间复杂度为 O(n),因为最坏情况下需要存储 n 个不同的前缀和。
C++ 实现
class Solution {
public:
int findMaxLength(vector<int>& nums) {
unordered_map<int, int> hash;
// 初始化前缀和为 0 的位置为 -1
hash[0] = -1;
int sum = 0;
int ret = 0;
for (int i = 0; i < nums.size(); ++i) {
// 0 记为 -1,1 记为 1
sum += (nums[i] == 0 ? -1 : 1);
if (hash.count(sum)) {
ret = (ret, i - hash[sum]);
} {
hash[sum] = i;
}
}
ret;
}
};


