📘 題目敘述
給定一個二元陣列 nums(只包含 0 與 1)以及整數 k。你最多可以把 k 個 0 翻成 1,請回傳翻完後「連續 1 的最長長度」。
條件限制
1 <= nums.length <= 10^5nums[i]是0或10 <= k <= nums.length
🧠 解題思路
這題我的核心想法是「維護一個滑動視窗 [l, r]」:
- 視窗內允許最多出現
k個0(代表:這些0都可以被當作翻成1) - 只要視窗內
0的數量> k,就代表「這個視窗不合法」- 這時要移動左指標
l,把視窗縮小到重新合法
- 這時要移動左指標
- 每當視窗合法時,就用
r - l + 1更新答案
簡單說,我找的是「最多包含 k 個 0 的最長子陣列長度」,因為那 k 個 0 就是可以翻掉的。
所有變數
l:滑動視窗的左端點(left pointer)r:滑動視窗的右端點(right pointer),用for逐步往右擴張count:目前視窗內的0的數量ans:目前找到的最長合法視窗長度nums:輸入的二元陣列k:最多允許翻轉的0數量(也就是視窗內最多允許的0數)
🪜 主要流程步驟
1. 右指標 r 往右擴張視窗
- 每次把
nums[r]納入視窗 - 如果
nums[r] == 0,就讓count++(表示多了一個要翻的 0)
2. 視窗不合法就縮小(重點)
當 count > k 時,代表:
- 視窗內的
0太多了 - 就算把
k個0翻掉,還會剩下0,所以這段不可能全部變成連續1
因此我用:
while (count > k)不斷移動l- 如果移出去的
nums[l] == 0,代表少了一個0,所以count-- l++,直到count <= k(視窗重新合法)
3. 視窗合法就更新答案
- 當
count <= k時,這個視窗[l, r]就是一段「最多含 k 個 0」的區間 - 翻掉裡面的
0後就能變成一段連續1 - 用
ans = max(ans, r - l + 1)更新最長長度
4. 為什麼這樣一定不會漏掉答案?
r從左到右走過每個位置,每個元素最多進視窗一次l也只會往右移,每個元素最多被移出一次- 對每個
r,我都維持「以 r 結尾的最長合法視窗」 - 所以全程取最大值,答案一定被涵蓋
5. 複雜度
- 時間:
O(n)(因為l、r都只會單調往右走) - 空間:
O(1)
💻 程式碼實作
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int l = 0;
int count = 0;
int ans = 0;
for (int r = 0; r < nums.size(); r++) {
if (nums[r] == 0)
count++;
while (count > k) {
if (nums[l] == 0)
count--;
l++;
}
ans = max(ans, r - l + 1);
}
return ans;
}
};