91. Max Consecutive Ones III
Given a binary array and an integer k, return the maximum number of consecutive 1s obtainable by changing at most k zeros to ones. Explain the sliding-window state, when the left boundary moves, and the time and space complexity.
I would use a sliding window. The right pointer expands the window one element at a time, while zero_count tracks how many zeros are inside it. If zero_count becomes greater than k, I repeatedly move the left pointer until the window is valid again. I then update the longest valid window. This works because each valid window contains at most k zeros. Both pointers move only forward, so the time complexity is O(n), and the auxiliary space complexity is O(1).
See the Code while reading this explanation.
The problem asks for the longest contiguous part of a binary array that can become all ones after changing at most k zeros. A sliding window is a good fit because it lets us expand a candidate subarray, count its zeros, and shrink it only when it requires more than k changes.
- What input sizes, value ranges, and edge cases should the solution handle?
- What output should be returned for empty, invalid, or duplicate input?
- Should I prioritize execution time or memory use, and may I use the standard library?
The input contains a binary array named nums and an integer k. Every array element is either 0 or 1.
We may change at most k zeros into ones. We must return the maximum length of a contiguous subarray that can become all ones.
The example is:
nums = [1, 1, 0, 0, 1, 1, 1, 0, 1] k = 2
The expected result is 7.
The window is the contiguous subarray from left to right, including both boundaries.
The right pointer expands the window. The variable zero_count stores the number of zeros currently inside it.
The main invariant is that after the shrinking loop finishes, the window contains at most k zeros. Therefore, every window used to update the answer can be changed into all ones with at most k changes.
Set left to 0 because the first window begins at the first array position.
Set zero_count to 0 because no values have entered the window yet.
Set max_ones to 0 because no valid window length has been recorded.
Then move right from index 0 through index 8.
At right = 0, nums[right] is 1. zero_count stays 0. The valid window length is 1, so max_ones becomes 1.
At right = 1, nums[right] is 1. zero_count stays 0. The window length is 2, so max_ones becomes 2.
At right = 2, nums[right] is
- zero_count becomes
- This is allowed because k is
- The window length is 3, so max_ones becomes 3.
At right = 3, nums[right] is 0. zero_count becomes 2. The window is still valid. Its length is 4, so max_ones becomes 4.
At right = 4, the value is
- zero_count remains
- The window length becomes 5, so max_ones becomes 5.
At right = 5, the value is 1. The window length becomes 6, so max_ones becomes 6.
At right = 6, the value is 1. The window from index 0 through index 6 is [1, 1, 0, 0, 1, 1, 1]. It contains two zeros, so it is valid. Its length is 7, and max_ones becomes 7.
At right = 7, nums[right] is 0. zero_count increases from 2 to 3. Now zero_count is greater than k, so the window must shrink repeatedly.
First, remove index 0. Its value is 1, so zero_count remains 3. left becomes 1.
Next, remove index 1. Its value is also 1, so zero_count remains 3. left becomes 2.
Next, remove index 2. Its value is 0, so zero_count decreases from 3 to 2. left becomes 3.
The valid window is now from index 3 through index 7. Its values are [0, 1, 1, 1, 0]. Its length is 5, so max_ones remains 7.
At right = 8, nums[right] is
- zero_count stays
- The valid window from index 3 through index 8 is [0, 1, 1, 1, 0, 1]. Its length is 6, so max_ones remains 7.
The final answer is 7. By changing the zeros at indices 2 and 3, the first seven values become [1, 1, 1, 1, 1, 1, 1].
The right pointer considers each new possible window ending position. If the window contains more than k zeros, the left pointer moves until the window contains at most k zeros again.
After shrinking, the current window is always valid. The algorithm records the largest length among these valid windows. Therefore, max_ones is the maximum number of consecutive ones obtainable after changing at most k zeros.
The for loop moves right through the array. When nums[right] is 0, the code increments zero_count.
The while loop runs when zero_count is greater than k. Before moving left, it checks whether nums[left] is 0. If it is, that zero is leaving the window, so zero_count is decremented. The code then increments left.
After the while loop, the window is valid. Its length is right - left + 1. The code compares this length with max_ones and keeps the larger value.
The time complexity is O(n). The right pointer visits each array element once. The left pointer also moves only forward and can move at most n times in total.
The auxiliary space complexity is O(1). The algorithm uses only a few integer variables and does not create storage that grows with the input.
If k is 0, the answer is the longest existing run of ones. If every value is 1, the answer is the full array length. If every value is 0, the answer is min(k, n). If k is at least the number of zeros, the answer is n. An empty array returns 0.
Use a variable-size sliding window. Expand the right boundary to include each new array value. Count how many zeros are inside the current window. A window is valid when zero_count is at most k because all of its zeros can be changed into ones. If zero_count becomes greater than k, move the left boundary repeatedly until the window is valid again. The central invariant is that every window used to update max_ones contains at most k zeros. This avoids examining every possible subarray separately.
from typing import List
def longestOnes(nums: List[int], k: int) -> int:
left = 0
zero_count = 0
max_ones = 0
for right, val in enumerate(nums):
if val == 0:
zero_count += 1
while zero_count > k:
if nums[left] == 0:
zero_count -= 1
left += 1
max_ones = max(max_ones, right - left + 1)
return max_ones
if __name__ == "__main__":
nums = [1, 1, 0, 0, 1, 1, 1, 0, 1]
k = 2
print(longestOnes(nums, k)) # 7The time complexity is O(n), where n is the length of nums. The right pointer moves across the array once. The left pointer also moves only forward and can move at most n times in total. The inner while loop does not make the total time O(n squared) because an element can leave the window only once. The auxiliary space complexity is O(1) because the algorithm stores only a fixed number of integer variables.
This sliding-window pattern is useful when software must find the longest or shortest contiguous range that stays within a limit. Examples include finding the longest period containing at most a certain number of failures, the largest event range with limited missing records, or the longest text segment containing at most a fixed number of special characters.
This question tests whether a candidate can recognize a variable-size sliding window. It checks whether the candidate can maintain a count while two boundaries move at different times. The interviewer also evaluates repeated shrinking, inclusive window-length calculation, and correct pointer order. Another important part is explaining why a for loop containing a while loop still takes O(n) total time when both pointers move only forward.
One mistake is using an if statement instead of a while loop when zero_count is greater than k. The window may need to remove several values before it becomes valid. Another mistake is forgetting to decrement zero_count when a zero leaves the left side. A candidate may also increment left before checking nums[left], which checks the wrong element. Another error is updating max_ones while the window is still invalid. Finally, this problem requires a contiguous subarray, not a subsequence.
State the invariant before writing the code: after the while loop finishes, the window from left through right contains at most k zeros. Then explain how each update preserves that invariant.









