剑指offer011-0和1个数相同的子数组
题目
给定一个二进制数组 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 <= 105nums[i]不是0就是1
注意:本题与主站 525 题相同: https://leetcode-cn.com/problems/contiguous-array/
思路
这个用前缀和,这种题目可以抽象出一个模板,两数之差
还是如剑指offer010所描述,我们可以保存一个前缀和数组
比如0,0,1,0,0,0,1,1
初始化数组sum,sum[i]表示0~i-1的和
即
| 0 | 0 | 0 | 1 | 1 | 1 | 1 | 2 | 2 |
|---|
我们考虑arr的子数组如何满足条件,即子数组0和1一直样多
很明显,对于0,0,1,1,如果要满足0的个数和1的个数一样多,只要满足 2*sum(0,0,1,1) = 数的个数 = 4
即2*(sum[j] - sum[i]) = j-(i+1)+1
因为sum[j]是 0-j,包含j
sum[i]是0-i,包含i
所以 sum[j] - sum[i] 是计算 i+1 ~j的和,他们的距离就是 j - (i+1) +1 = j - i
因此,整个问题就变成了从数组sum中找到两个数满足
2 * (sum[j] - sum[i]) = j - i
变形一下就变成
2sum[j] - j = 2sum[i] -i
整个形式比较特殊,我们先按照一般的理解,2sum[j] - j -(2sum[i] -i) = 0
我们不妨换元,即a =2sum[i] - i,b =2sum[j] - j
也就是 a-b = 0
又回到了两数之差等于定值0
1 | for (int i = 0; i < sum.length; i++) { |
在结合题目的意思,我们要求最大的范围,也就是当a进入map的时候,我们要保存a的index,当a再次进入map的时候,我们取最小值,【实际上不需要操作,因为前面a的index肯定小于后面】
1 | Map<Integer, Integer> map = new HashMap<>(); |
【实际上不需要操作,因为前面a的index肯定小于后面】
1 | class Solution { |