题目描述
给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
注意:
0 ≤ x, y < 231.
示例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
思路:前缀和 + 哈希表
我们在预处理前缀和时,将 nums[i] 为 0 的值当做 −1 处理。
从而将问题转化为:如何求得最长一段区间和为 0 的子数组。
同时使用哈希表来记录某个前缀和出现的最小下标是多少。
java 代码
class Solution {
public int findMaxLength(int[] nums) {
int n = nums.length;
int res = 0; // 用于记录返回结果
if (n == 1) { // 如果数组长度为1,0和1的数量不可能相等
return 0;
}
int[] sum = new int[n+1]; // 用于记录前缀和
for(int i = 1; i <= n; i++) {
sum[i] = sum[i-1] + (nums[i-1] == 1 ? 1 : -1); // sum[i]代表下标i之前(不包括下标i)的前缀和,注意要将 nums[i] 为 0 的值当做 −1 处理
}
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i <= n; i++) {
if(!map.containsKey(sum[i])) { // 如果哈希表中不存在此前缀和,则将此前缀和存入哈希表中,key为前缀和,val为前缀和第一次出现时的下标
map.put(sum[i], i);
} else {
int preIndex = map.get(sum[i]); // 如果哈希表中存在此前缀和,首先取出此前缀和和第一次出现时的下标preIndex,sum[preIndex] = sum[i],故下标[preIndex+1, i]范围内的子数组的和为0
res = Math.max(res, i - preIndex); // 取和为0的子数组的最大长度
}
}
return res;
}
}