文章目录
- ⛏1. 题目
- 🗡2. 算法原理
- ⚔解法一:暴力枚举
- ⚔解法二:前缀和+哈希表
- ⚒3. 代码实现
⛏1. 题目
题目链接:525. 连续数组 - 力扣(LeetCode)
给定一个二进制数组 nums
, 找到含有相同数量的 0
和 1
的最长连续子数组,并返回该子数组的长度。
示例 1:
输入: nums = [0,1]
输出: 2
说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。
示例 2:
输入: nums = [0,1,0]
输出: 2
说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。
提示:
1 <= nums.length <= 105
nums[i]
不是0
就是1
🗡2. 算法原理
⚔解法一:暴力枚举
直接枚举所有子数组,判断是否符合要求,这不做示例。
复杂度较高,大概率超时
⚔解法二:前缀和+哈希表
这题的意思是让我们找出一个最长连续的区域,让这个区域内的0
和1
数量相等,如果我们直接统计这个0
和1
的数目的话,还是比较困难的。我们可以换个思路,反正这里就0
和1
两个数字,我们不妨将0
看作-1
,那么这题就转换成了在这个数组中,找出一段连续的区域,让这个区域内的和0
。
这样转换之后,就和这题类似:前缀和+哈希表——560. 和为 K 的子数组,这是这里找的是和为0
的最长子数组,那么这题就可以用前缀和+哈希表。
不了解的可以点击链接看一下这题:
设i
为数组中的任意位置,用sum[i]
表示[0,i]
区间内的所有元素和,找到在[0,i-1]
位置第一次出现sum[i]
的位置即可
细节还是较多:
- 哈希表中存什么?
这里要的是最长的子数组,所以我们要的是下标,所以哈希表里面要建立前缀和与数组下标的映射关系.- 存入哈希表的时机:当这个下标对应的前缀和使用完毕之后,再丢入哈希表。
- 如果有重复的
<sum,i>
,我们选取的是靠左侧的下标,因为我们选取的是最长子数组,越靠近左侧,这个子数组就越长
- 默认前缀和为
0
时,应该去[-1,0]
这个区间去找,所以当我们用hash[0] = -1
来表示默认前缀和为0
。- 长度计算,直接看下图,清晰明了:
时间复杂度为O(n)
⚒3. 代码实现
class Solution {
public:int findMaxLength(vector<int>& nums){unordered_map<int,int> hash;hash[0] = -1; //默认前缀和为0的情况int sum = 0,ret = 0;for(int i=0;i<nums.size();i++){sum+=nums[i]==0?-1:1;if(hash.count(sum))ret = max(ret,i-hash[sum]); //选取最长的子数组elsehash[sum] = i;}return ret;}
};
运行结果: