525.连续数组
525.连续数组
题目
原题 525.连续数组
解题
1.未优化版本 滑动窗口思想
最先想到的是使用滑动窗口的方法,先使用 preOneCount[i]
计算 [0,i]
区间内 1
出现的次数,然后通过从大往小遍历滑动窗口 window
去检测窗口是否合法(即窗口所在的区间内部 1
和 0
的数量是否一致)
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int findMaxLength(int[] nums) {
int n = nums.length;
int[] preOneCount = new int[n];
preOneCount[0] = nums[0]==1?1:0;
for(int i=1; i<nums.length; i++){
preOneCount[i]=(nums[i]==1)?preOneCount[i-1]+1:preOneCount[i-1];
}
// window 计算
for (int window = n; window>=1; window--){
for (int i=0; i<=n-window; i++){
int oneCount = preOneCount[i+window-1] - ((i>=1)?preOneCount[i-1]:0);
int zeroCount = window-oneCount;
if (oneCount==zeroCount){
return window;
}
}
}
return 0;
}
}
2.使用 HashMap + 自定义前缀和优化
可以使用 HashMap 去优化代码,换一个角度思考问题
- 首先,前缀和并不一定是要累加
nums[i]
,可以自定义累加规则 - 所以可以结合
nums
仅包含0,1
的特性去定义一个preSum
,在遍历区间(i, j]
的过程中,遇到0
就对preSum-1
,否则就+1
,那么如果区间(i, j]
内部出现的0
和1
数量是相同的,就会存在preSum[i]=preSum[j]
- 在计算完
preSum
之后(这个过程类似之前计算preOneCount
,都是为了下一步计算res
进行辅助),可以考虑在遍历过程中引入HashMap
,HashMap
会暂存Entry(preSum[i],i)
,这样在遍历到preSum[j]
的时候,如果preSum[j]=preSum[i]
,那么就可以根据j
和i
拿到一个区间去更新res
。 - 上述记录
Entry
到HashMap
的时候,只需要记录value
第一次出现的index
位置就行,这样能够尽可能长的获得到区间。
具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int findMaxLength(int[] nums) {
int n = nums.length;
int[] preSum = new int[n + 1];
int res = 0;
// 计算 preSum,遇到 1 则 +1, 遇到 0 则 -1.
// 从 preSum[i] 到 preSum[j] 的过程中,如果经历了相同数量的 0 和 1, 那么一定有 preSum[j]=preSum[i]
for (int i = 1; i < n + 1; i++) {
preSum[i] = (nums[i-1] == 1) ? preSum[i - 1] + 1 : preSum[i - 1] - 1;
}
// 利用 HashMap O(n) 优化遍历
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < n+1; i++) {
int sum = preSum[i];
if (map.containsKey(sum)) {
int leftIndex = map.get(sum);
res = Math.max(res, i - leftIndex);
} else {
// 仅记录第一次出现 sum 的 idx, 这样可以保持区间最长
map.put(sum, i);
}
}
return res;
}
}
本文由作者按照 CC BY 4.0 进行授权