LeetCode #1004 Medium

Max Consecutive Ones III

Given a binary array and an integer k, return the length of the longest subarray of 1s after flipping at most k zeros.

sliding-windowtwo-pointersarray
Open on LeetCode ↗
02

Intuition

The trap is trying to simulate the flips: pick which zeros to flip, then measure the run. You never actually flip anything. A window of 1s-after-flipping-k-zeros is achievable exactly when the window contains at most k zeros, so the problem is really "longest window with at most k zeros" wearing a costume. Once you restate it that way, it is the standard grow-then-shrink template, not a simulation problem at all.

How to spot this pattern

"Flip at most k zeros" is a window whose validity is zeros <= k. You never actually flip anything — you just refuse to let the window contain more than k zeros. Any "change at most k elements" question reduces to counting the changeable elements inside a window.

03

Approach

1

Restate the flipping as a counting constraint

You never actually need to flip anything. A window is achievable exactly when the number of zeros inside it is at most k, so the answer is the widest such window. This restatement is the whole trick — the brute force of trying every subarray and counting its zeros is O(n^2) and does no more work conceptually.

2

Grow right, shrink left

Advance right one step at a time, incrementing zeros whenever nums[right] == 0. If zeros > k the window is now illegal, so advance left, decrementing zeros when the element leaving is a zero. Because both pointers only ever move forward, the total work is O(n) despite the nested-looking loops.

3

Record the answer after every legal state

Once the inner shrink loop finishes, the window is valid again, so update best = max(best, right - left + 1). Note that the shrink is a while, not an if — that distinction matters in the variants where a single step out can remove more than one unit of the constraint, and keeping it a while here means the same template transfers unchanged. O(n) time, O(1) space.

04

Solution & live demo

1class Solution:
2 def longestOnes(self, nums, k):
3 left = zeros = best = 0
4 for right, v in enumerate(nums):
5 if v == 0:
6 zeros += 1
7 while zeros > k:
8 if nums[left] == 0:
9 zeros -= 1
10 left += 1
11 best = max(best, right - left + 1)
12 return best
05

Common pitfalls

Decrementing zeros for every element leaving the window

✗ Wrong
left += 1
zeros -= 1
✓ Right
if nums[left] == 0:
    zeros -= 1
left += 1

Only zeros contribute to the counter, so removing a 1 must leave it untouched. Decrementing unconditionally drives the count negative and lets the window swallow far more than k zeros.

Actually mutating the array

✗ Wrong
nums[i] = 1
flips += 1
✓ Right
if v == 0:
    zeros += 1

Flipping in place destroys the information needed when the window's left edge passes back over that index, so the count can never be undone. Counting instead of mutating keeps every step reversible.

Shrinking on zeros >= k

✗ Wrong
while zeros >= k:
✓ Right
while zeros > k:

Exactly k zeros is allowed — that's the budget, not the limit to stay under. The strict version shrinks one step too early and reports answers consistently short by one flip's worth.

06

Edge cases

k = 0

The window may hold no zeros, which degenerates to the plain longest run of 1s.

k >= number of zeros

The whole array is flippable, so the answer is n.

All zeros

The answer is k, capped by the array length.

Empty array

No window exists and 0 is returned.

07

Complexity

Time
O(n)
Space
O(1)
Each pointer crosses the array once, so it is linear despite the nested loop.