1.題目描述
2.題目鏈接
1004. 最大連續1的個數 III - 力扣(LeetCode)?
3.代碼解答
class Solution {public int longestOnes(int[] nums, int k) {int zero=0,length=0;for(int left=0,right=0;right<nums.length;right++){if(nums[right]==0){zero++;}while(zero>k){if(nums[left]==0){zero--;}left++;}length=Math.max(length,right-left+1);}return length;}
}
?4.解題思路
題目要求將最多k個0反轉,也就是最多將k個0全部變為1,求數組中最長的全是1的子串。
我們先定義兩個指針left和right,讓他們都指向數組中的首元素。數組如下例子:
這時k=2,也就是說,我們最多可以將2個0反轉為1,我們可以將第四個和第五個0反轉為1,這時的連續1的個數就是5,或者將倒數第1個和第2個0反轉,這時連續1的個數就是6。
我們先讓left保持不動,讓right指針從前往后遍歷數組,再定義一個zero計數器,用來計算right到left之間子串的0的個數。
當zero>k時,right指針停止移動。
?
這時right之前的子串就是我們要求的子串。?
那么下一個子串如何尋找?right還需要往后遍歷嗎?
right不需要往后遍歷了,因為只要子串的起始元素是left,那么現在right指向的0就已經超過題目要求的k個0的要求了。
那么left怎么移動?一個一個遍歷數組嗎?
當然不必,因為括號部分的0已經超過了題目中要求的最多k個0,left指針只要指向括號0部分之前,right結束位置都不會變。
那么left應該怎么移動呢?
left不用回退,保持自增,每略過一個0就使zero計數器-1,直到zero<=k,這時才又重新滿足要求。也就是如下位置:?
?
而right也不必回退,因為此時right到left之間的子串已經合法了(zero<=k),所以right繼續遍歷數組即可。
我們不斷更新length的值,直到right遍歷完數組,返回最后保留下來的length即可。
所以我們發現,在整個過程中,left和right都不回退,而是一直保持同向移動,這也是我們非常熟悉的滑動窗口了。
- 滑動窗口邏輯:
- 右指針擴展窗口,遇到 0 時增加 zero 計數
- 當 zero 超過 k 時,左指針右移以收縮窗口
- 窗口合法時,記錄當前窗口長度
5.代碼細節
這里可以用while嗎?
if(nums[right]==0){zero++;}
當然不可以,因為如果使用while,當right指針碰上while時,while循環永遠無法結束,zero會一直自增,直至超出內存限制。
這里if處理右指針遇到的單個 0(擴展窗口)。
那為什么這里可以用while?
while(zero>k){if(nums[left]==0){zero--;}left++;}
需要持續收縮窗口,直到窗口重新合法(可能需要移除多個 0)。?
因為while中left一直在自增,那么right到left之間的子串中包含的0的個數也就總會減少,直到zero<=k,while循環自然也就結束了。