題目:
給定一個二進制數組 nums
, 找到含有相同數量的 0
和 1
的最長連續子數組,并返回該子數組的長度。
媽的 連題目都沒有讀懂!本來看成是找到兩個連續子數組,兩個連續子數組的 0 1 個數分別相同,我說怎么看著如此復雜。
題目轉換:
在一個數組里找到一個連續子數組,其中0和1 的數量是一致的,求最大的連續子數組的長度。
解題過程
暴力:
遍歷所有連續子數組的0和1 的個數,如果相同,則維護這個連續子數組的最大長度。
巧妙的轉換:
相同數量的0和1 ? 將 0 → -1 ? 連續子數組和 為 0
如果想要求子數組的元素和 ? 計算數組的前綴和。
prefixSum[i] : [0…i] 的前綴和,元素的累加。
[i…k] 的元素累加和 = prefixSum[k]-prefixSum[i-1]
所以:相同數量的0和1 ? 將 0 → -1 ? 連續子數組和 為 0 ? prefixSum[k]-prefixSum[i] = 0 長度為 i- k ? 當出現前綴和相同時維護一個最大的長度。
思路1:(x)
- 維護一個prefixSum表。遍歷nums
- 用兩個for循環,遍歷所有子數組。
思路2:
- 用一個map記錄前綴和和第一次出現的位置。key?value 的形式。
- map.has 意味著出現了前綴和一致的情況,則維護最大長度。
/*** @param {number[]} nums* @return {number}*/
var findMaxLength = function(nums) {let max = 0;// 如果連續子數組索引從0開始,則是priefix-prefix[-1],因此要提前保存-1,但是很難想到。const map = new Map();map.set(0,-1)let counter = 0;for (let i = 0; i < nums.length; i++) {if (nums[i] === 0) {counter--;} else {counter++;}if (map.has(counter)) {max = Math.max(max, i - map.get(counter));} else {map.set(counter, i);}}return max;
};
思路3:
最長的連續子數組是以index = 0 為開頭的特殊情況,要么使用思路二,在map里添加 index = -1 的情況。
要么使用思路三:sum = 0 的情況,sum是從index = 0 開始算的,相當于算的就是每個以index = 0 為開頭的連續子數組的和。
/*** @param {number[]} nums* @return {number}*/
var findMaxLength = function(nums) {let max = 0;const map = new Map();let sum = 0;for (let i = 0; i < nums.length; i++) {if (nums[i] === 0) {sum --;} else {sum ++;}if(sum === 0){max = Math.max(max,i+1)}else if (map.has(sum)) {max = Math.max(max, i - map.get(sum));} else {map.set(sum , i);}}return max;
};