1004. Max Consecutive Ones III

練習日期:2026-01-30

難度:Medium

類型:Array、Binary Search、Sliding Window、Prefix Sum

📘 題目敘述

給定一個二元陣列 nums(只包含 01)以及整數 k。你最多可以把 k0 翻成 1,請回傳翻完後「連續 1 的最長長度」。

條件限制

  • 1 <= nums.length <= 10^5
  • nums[i]01
  • 0 <= k <= nums.length

🧠 解題思路

這題我的核心想法是「維護一個滑動視窗 [l, r]」:

  • 視窗內允許最多出現 k0(代表:這些 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 太多了
  • 就算把 k0 翻掉,還會剩下 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)(因為 lr 都只會單調往右走)
  • 空間: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;
    }
};

https://leetcode.com/problems/max-consecutive-ones-iii/

作者: scottnick
撰寫日期: 2026-01-30
類別:
原文連結: https://scottnick.github.io/cpp-notes/leetcode75/1004-max-consecutive-ones-iii.html