Max Consecutive Ones III
Initial Approach
Declare a counter to keep track of maximum number of consecutive ones Initialize zero count to k Traverse the input array Keep incrementing the counter as long as 1 is the element in the array If there is a 0, decrement the zero count If the zero count becomes -1, reset it to k and reset ones count to 0 Update the maximum we have found so far as we traverse through the array
Mistakes
- Missed to identify the invariant
- Missed the subarray size formula. This can only be found at coding stage. Not at high level outline of the solution.
Brute-Force Solution
The brute-force solution would involve generating all possible subarrays, flipping at most k
zeroes to ones in each, and then checking the length of consecutive ones. Here’s how you could do it:
- Loop through the array to find all subarrays.
- For each subarray, count the number of zeroes and ones.
- If the number of zeroes is less than or equal to
k
, find the length of the subarray. - Keep track of the maximum length of such subarrays.
This would involve nested loops and would be highly inefficient. Specifically, the time complexity would be (O(n^2)), where (n) is the length of the array.
Here’s some pseudocode for a brute-force solution:
|
|
The above algorithm doesn’t actually flip the zeroes to ones but counts them to see if flipping would be possible within the given constraint of at most k
flips. Also, the max_length is limited by the total length of the array.
Unnecessary Work
The unnecessary repeated work in the brute-force approach occurs mainly in two areas:
Subarray Enumeration: For every subarray starting at index
i
and ending at indexj
, the algorithm goes through the elements to count the zeros and ones. This means the same elements get recounted multiple times for overlapping subarrays.Zero and One Counting: The number of zeros and ones within any given subarray is recalculated from scratch each time, even though this information could be incrementally updated from a previously calculated smaller subarray.
For example, if you’ve already calculated the number of zeros and ones for the subarray [i, j]
, you don’t need to recalculate everything for [i, j+1]
. You can simply look at the new element nums[j+1]
and update your counts accordingly.
Both of these issues lead to a time complexity of (O(n^2)) because you are looping through the array multiple times for each subarray.
Optimized approaches would try to eliminate this redundant work to improve efficiency.
Better Approach
This problem is about finding the maximum length of a subarray with consecutive 1’s, where you are allowed to flip at most k
zeros to 1’s.
You are given a binary array nums
and an integer k
. The task is to find the maximum number of consecutive 1’s in the array if you can flip at most k
0’s.
In this problem, the invariant is the number of zeroes you are allowed to flip (k
). While iterating through the array, you can count the zeroes encountered and compare it to k
. The number of zeroes should never exceed k
for any subarray that you are considering as a valid solution.
You can solve this problem using the sliding window technique:
- Initialize two pointers,
left
andright
, to 0. - Initialize
max_length
to 0 andzero_count
to 0. - Iterate
right
from 0 to length of array:- If
nums[right]
is 0, incrementzero_count
. - While
zero_count > k
, ifnums[left]
is 0, decrementzero_count
. Moveleft
one step to the right. - Update
max_length
asmax(max_length, right - left + 1)
.
- If
By keeping zero_count <= k
, you ensure the invariant holds.
In the context of this problem, the loop invariant is the condition that the zero_count
must not exceed k
for any valid subarray being considered.
Specifically, during each iteration of the loop:
zero_count
keeps track of the number of zeros in the current subarray defined by[left, right]
.- The while-loop inside ensures that
zero_count
is always less than or equal tok
.
This invariant helps us maintain a valid subarray [left, right]
where at most k
zeroes can be flipped to ones, allowing us to find the maximum length of such a subarray.
In this problem, the invariant and the loop invariant are different but related.
Invariant: The more general rule for the problem is that in any valid subarray, you can have at most
k
zeroes that can be flipped to ones. This is a condition that your final answer must satisfy but is not necessarily maintained throughout each iteration of your algorithm.Loop Invariant: During each iteration of the loop, the condition maintained is that
zero_count <= k
. This is checked and enforced during each cycle of the loop to ensure that the subarray[left, right]
is valid according to the problem’s constraints.
So, while the invariant describes a condition that the solution must meet, the loop invariant is a condition maintained throughout the loop to ensure that you reach the correct solution.
In the sliding window algorithm, the loop invariant is: “The subarray between left
and right
contains at most k
zeros.”
The algorithm maintains this invariant through each iteration of the loop:
Initialization: At the start,
left
andright
are both 0, andzero_count
is 0. The subarray betweenleft
andright
is empty, so it trivially contains at mostk
zeros. The invariant holds.Maintenance: On each iteration, you move the
right
pointer one step to the right. If you encounter a zero, you incrementzero_count
. Ifzero_count
exceedsk
, you start moving theleft
pointer to the right untilzero_count
is back to at mostk
. This ensures the loop invariant is maintained.Termination: When the loop ends, you’re guaranteed that the longest subarray you’ve found (stored in
max_length
) is the longest subarray containing at mostk
zeros. The invariant helps you confidently state this.
So, by maintaining the loop invariant, the algorithm ensures that at each step, the subarray between left
and right
is a valid candidate for a solution to the problem. This allows you to efficiently keep track of the maximum length of such valid subarrays.
Solution
A sliding window approach can be used to solve this problem. You can maintain a window within the array, and if you find a 0, increment a counter. If the counter exceeds k
, shrink the window from the left. The maximum length of the window during this process will be your answer.
Here is the code in Python:
|
|
Explanation
- We use two pointers
left
andright
to represent the current window within the array. - We iterate through the array using
right
pointer and whenever we find a 0, we increment thezero_count
. - If
zero_count
exceedsk
, we shrink the window from the left by incrementing theleft
pointer until thezero_count
becomes equal tok
. - At each step, we update
max_length
with the current window size if it’s greater than the currentmax_length
. - Finally, we return the
max_length
, which is the maximum length of consecutive 1’s that can be achieved by flipping at mostk
zeros.
This code runs in O(n) time complexity and O(1) space complexity, where n is the length of the nums
array.
title: Max Consecutive Ones III excerpt: This covers using the basic building blocks such as counter to maintain the constraint two pointers and sliding window. tags: counter-to-maintain-constraint two-pointers sliding-window
Given a binary array nums and an integer k, return the maximum number of consecutive 1’s in the array if you can flip at most k 0’s.
Example 1:
Input: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
Output: 6
Explanation: [1,1,1,0,0,1,1,1,1,1,1]
Bolded numbers were flipped from 0 to 1. The longest subarray is underlined.
Example 2:
Input: nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], k = 3
Output: 10
Explanation: [0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
Bolded numbers were flipped from 0 to 1. The longest subarray is underlined.
Constraints
- 1 <= nums.length <= 105
- nums[i] is either 0 or 1.
- 0 <= k <= nums.length
Solution Outline
Consider the example:
0 1 2 3 4 5 6 7 8 9 10
[1,1,1,0,0,0,1,1,1,1,0]
i
j
longest = 5
i = 0
j = 4
j - i + 1 = longest (you cannot exceed k number of 0s)
When j moves to 5, we violate the constraint. What should we do to make the 0s less than or equal to k? Increment the i index. Until we get to a location where i and j only have at most k 0s. So stop at i = 4
What should we do next? We increment j until we only have max 1s and 0s < k. The index j stops at 9.
9 - 4 + 1 = 6
So, longest = 6
We now have a new longest value, we update the longest variable to 6. What should we do next? The reason we increase i is to drop off a zero (we are trying maintain the constraint). The reason we increment j is to see if we can extend the next element into our current subarray size. We increment j. We have a 0, which means number of 0s exceed k j has reached the last index, we can terminate. Return longest as the result.
|
|
Building Blocks
- Counter to Maintain the Constraint
- Two Pointers