1. 程式人生 > >[LeetCode] Max Consecutive Ones II 最大連續1的個數之二

[LeetCode] Max Consecutive Ones II 最大連續1的個數之二

Given a binary array, find the maximum number of consecutive 1s in this array if you can flip at most one 0.

Example 1:

Input: [1,0,1,1,0]
Output: 4
Explanation: Flip the first zero will get the the maximum number of consecutive 1s.
    After flipping, the maximum number of consecutive 1s is 4.

Note:

  • The input array will only contain 0 and 1.
  • The length of input array is a positive integer and will not exceed 10,000

Follow up:
What if the input numbers come in one by one as an infinite stream? In other words, you can't store all numbers coming from the stream as it's too large to hold in memory. Could you solve it efficiently?

這道題在之前那道題Max Consecutive Ones的基礎上加了一個條件,說我們有一次將0翻轉成1的機會,問此時最大連續1的個數,再看看follow up中的說明,很明顯是讓我們只遍歷一次陣列,那我們想,肯定需要用一個變數cnt來記錄連續1的個數吧,那麼當遇到了0的時候怎麼處理呢,因為我們有一次0變1的機會,所以我們遇到0了還是要累加cnt,然後我們此時需要用另外一個變數cur來儲存當前cnt的值,然後cnt重置為0,以便於讓cnt一直用來統計純連續1的個數,然後我們每次都用用cnt+cur來更新結果res,參見程式碼如下:

解法一:

class Solution {
public
: int findMaxConsecutiveOnes(vector<int>& nums) { int res = 0, cur = 0, cnt = 0; for (int num : nums) { ++cnt; if (num == 0) { cur = cnt; cnt = 0; } res = max(res, cnt + cur); } return res; } };

上面的方法有侷限性,如果題目中說能翻轉k次怎麼辦呢,我們最好用一個通解來處理這類問題。我們可以維護一個視窗[left,right]來容納至少k個0。我們遇到了0,就累加zero的個數,然後判斷如果此時0的個數大於k,那麼我們我們右移左邊界left,如果移除掉的nums[left]為0,那麼我們zero自減1。如果不大於k,那麼我們用視窗中數字的個數來更新res,參見程式碼如下:

解法二:

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int res = 0, zero = 0, left = 0, k = 1;
        for (int right = 0; right < nums.size(); ++right) {
            if (nums[right] == 0) ++zero;
            while (zero > k) {
                if (nums[left++] == 0) --zero;
            }
            res = max(res, right - left + 1);
        }
        return res;
    }
};

上面那種方法對於follow up中的情況無法使用,因為nums[left]需要訪問之前的數字。我們可以將遇到的0的位置全都儲存下來,這樣我們需要移動left的時候就知道移到哪裡了:

解法三:

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int res = 0, left = 0, k = 1;
        queue<int> q;
        for (int right = 0; right < nums.size(); ++right) {
            if (nums[right] == 0) q.push(right);
            if (q.size() > k) {
                left = q.front() + 1; q.pop();
            }
            res = max(res, right - left + 1);
        }
        return res;
    }
};

類似題目:

參考資料: