前缀和算法实战:连续数组与矩阵区域和
031 连续数组
题目描述: 给定一个二进制数组 nums,找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
暴力解法分析
暴力枚举所有子区间并验证显然会超时。我们直接看优化思路。
核心思路:前缀和 + 哈希表
其实稍微转化一下题目,就会变成我们熟悉的题——
- 本题让我们找出一段连续的区间,其中 0 和 1 出现的次数相同;
- 如果将 0 记为 -1,1 记为 1,问题就变成了找出一段区间,这段区间的和等于 0;
- 于是,这道题就和「和为 K 的子数组」的思路一样了。
设 sum[i] 表示 [0, i] 区间内所有元素的和(转换后)。
想知道最大的以 i 结尾的和为 0 的子数组,就要找到从左往右第一个 x 使得 [x, i] 区间内的所有元素的和为 0。那么 [0, x-1] 区间内的和是不是就是 sum[i] 了?
于是这个问题就变成了——在 [0, i-1] 区间内,第一次出现 sum[i] 的位置即可。
我们不用真的初始化一个前缀和数组,因为我们只关心在 i 位置之前,第一个前缀和等于 sum[i] 的位置。因此,我们仅需用一个哈希表,一边求当前位置的前缀和,一边记录第一次出现该前缀和的位置。
注意: 初始化时需要在哈希表中存入
{0: -1},这代表前缀和为 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.(sum)) {
ret = (ret, i - hash[sum]);
} {
hash[sum] = i;
}
}
ret;
}
};


