A clear explanation of finding the longest subarray of ones by flipping at most k zeros using a sliding window.
Problem Restatement
We are given a binary array nums and an integer k.
We can flip at most k zeros to ones.
We need to return the maximum number of consecutive ones in the array after performing at most k flips.
The official constraints state that 1 <= nums.length <= 10^5, nums[i] is either 0 or 1, and 0 <= k <= nums.length.
Input and Output
| Item | Meaning |
|---|---|
| Input | Binary array nums and integer k |
| Output | Length of longest subarray of all ones after at most k flips |
| Flip | Change 0 to 1 |
Function shape:
def longestOnes(nums: list[int], k: int) -> int:
...Examples
Example 1:
nums = [1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0]
k = 2Flip two zeros at indices 9 and 10:
[1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1]But a better choice flips zeros at indices 3 and 4 or 9 and 10 to get:
The optimal window is from index 3 to 10, flipping two zeros.
Answer:
6Example 2:
nums = [0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1]
k = 3Flip zeros at indices 4, 5, and 9 to get a window of 10 ones.
Answer:
10Key Insight
We want the longest window [left, right] that contains at most k zeros.
Use a sliding window:
- Expand the right end.
- If the window has more than
kzeros, shrink the left end. - Track the maximum window size.
Algorithm
- Use two pointers
left = 0andright = 0. - Track
zeros, the count of zeros in the current window. - For each
right:- If
nums[right] == 0, incrementzeros. - While
zeros > k, ifnums[left] == 0, decrementzeros. Moveleftright. - Update the maximum length as
right - left + 1.
- If
- Return the maximum length.
Correctness
At every step, the window [left, right] contains exactly zeros zeros.
When zeros > k, we shrink the left side until zeros <= k again.
Since both pointers only move right, each element is added and removed at most once.
The maximum window size found over all positions is the answer, because every valid window is considered.
Edge Cases
- Check the smallest and largest valid search values; off-by-one errors usually appear at the boundaries.
- Decide whether the predicate is looking for the first true value, the last true value, or an exact match.
- When the target is absent, the loop should still terminate and return the problem-specific failure value.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Each pointer moves left to right once |
| Space | O(1) | Only a few variables |
Common Pitfalls
- Do not mix inclusive and half-open bounds inside the same loop.
- Make sure each branch strictly reduces the search interval.
Implementation
class Solution:
def longestOnes(self, nums: list[int], k: int) -> int:
left = 0
zeros = 0
best = 0
for right in range(len(nums)):
if nums[right] == 0:
zeros += 1
while zeros > k:
if nums[left] == 0:
zeros -= 1
left += 1
best = max(best, right - left + 1)
return bestCode Explanation
We expand the window to the right:
for right in range(len(nums)):
if nums[right] == 0:
zeros += 1When the zero count exceeds k, shrink from the left:
while zeros > k:
if nums[left] == 0:
zeros -= 1
left += 1After adjustment, the window is valid. Update the best:
best = max(best, right - left + 1)Testing
def run_tests():
s = Solution()
assert s.longestOnes([1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0], 2) == 6
assert s.longestOnes([0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1], 3) == 10
assert s.longestOnes([1, 1, 1], 0) == 3
assert s.longestOnes([0, 0, 0], 0) == 0
assert s.longestOnes([0, 0, 0], 3) == 3
print("all tests passed")
run_tests()| Test | Expected | Why |
|---|---|---|
k=2 example | 6 | Flip two zeros in optimal window |
k=3 example | 10 | Flip three zeros in optimal window |
| All ones | 3 | No flips needed |
All zeros, k=0 | 0 | Cannot flip any |
All zeros, k=3 | 3 | Flip all three |