Longest run of ones after k flips
Given a binary array bits and an integer k, you may change at most
k zeros into ones. Return the length of the longest run of consecutive ones you can produce.
Examples
| Input | Output | Why |
|---|---|---|
bits = [1,1,1,0,0,0,1,1,1,1,0], k = 2 | 6 | Flip the zeros at 4 and 5: indices 4 to 9. |
bits = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], k = 3 | 10 | Indices 2 to 11 hold ten elements, three of them zeros. |
bits = [0,0,0], k = 0 | 0 |
Constraints
- 1 ≤ n ≤ 10⁵
- bits[i] is 0 or 1
- 0 ≤ k ≤ n
Hints
Hint 1
You never need to decide which zeros to flip one by one. Which runs can become all ones?
Hint 2
A run can be made all ones exactly when it contains at most k zeros.
Hint 3
Window with a zero counter: grow, and while the counter exceeds k, move the left end past a zero.
Where people lose marks
- Simulating flips, which leads to exponential or quadratic searches.
- Decrementing the zero count when any element leaves, instead of only when a zero leaves.
Dry run on [1,1,1,0,0,0,1,1,1,1,0],2
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 11bits10lo/hi111203040516171819010zeros0best1
1 enters. Longest so far: 1.
-
Step 2 / 11bits10lo11hi1203040516171819010zeros0best2
1 enters. Longest so far: 2.
-
Step 3 / 11bits10lo1112hi03040516171819010zeros0best3
1 enters. Longest so far: 3.
-
Step 4 / 11bits10lo111203hi040516171819010zeros1best4
0 enters: 1 zero inside. Longest so far: 4.
-
Step 5 / 11bits10lo11120304hi0516171819010zeros2best5
0 enters: 2 zeros inside. Longest so far: 5.
-
Step 6 / 11bits1011120304lo05hi16171819010zeros2best5
0 enters: 3 zeros inside. More than 2 zeros, so move lo from 0 to 4, past a zero.
-
Step 7 / 11bits1011120304lo0516hi171819010zeros2best5
1 enters.
-
Step 8 / 11bits1011120304lo051617hi1819010zeros2best5
1 enters.
-
Step 9 / 11bits1011120304lo05161718hi19010zeros2best5
1 enters.
-
Step 10 / 11bits1011120304lo0516171819hi010zeros2best6
1 enters. Longest so far: 6.
-
Step 11 / 11bits101112030405lo16171819010hizeros2best6
0 enters: 3 zeros inside. More than 2 zeros, so move lo from 4 to 5, past a zero.
How to think about it
The question sounds like a choice of which zeros to flip, but it is not. A stretch of the array can be turned into ones exactly when it holds at most k zeros, so the answer is the longest stretch with at most k zeros. That property survives shrinking, so the variable window applies, and its whole state is the number of zeros inside.
Rephrasing the question into a property of a contiguous run is the real skill here. Interviewers often describe the operation ("flip", "replace", "delete") to hide the window.
Complexity. Time O(n) · Space O(1)
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def longest_ones(bits, k):
best = lo = zeros = 0
for hi, b in enumerate(bits):
zeros += b == 0
while zeros > k: # too many zeros to flip: shrink
zeros -= bits[lo] == 0
lo += 1
best = max(best, hi - lo + 1)
return best#include <vector>
#include <algorithm>
int solve(const std::vector<int>& bits, int k) {
int best = 0, lo = 0, zeros = 0;
for (int hi = 0; hi < (int)bits.size(); ++hi) {
zeros += bits[hi] == 0;
while (zeros > k) zeros -= bits[lo++] == 0; // too many zeros to flip: shrink
best = std::max(best, hi - lo + 1);
}
return best;
}class Solution {
public int longestOnes(int[] bits, int k) {
int best = 0, lo = 0, zeros = 0;
for (int hi = 0; hi < bits.length; hi++) {
if (bits[hi] == 0) zeros++;
while (zeros > k) if (bits[lo++] == 0) zeros--; // too many zeros to flip: shrink
best = Math.max(best, hi - lo + 1);
}
return best;
}
}function longestOnes(bits, k) {
let best = 0, lo = 0, zeros = 0;
for (let hi = 0; hi < bits.length; hi++) {
if (bits[hi] === 0) zeros++;
while (zeros > k) { // too many zeros to flip: shrink
if (bits[lo] === 0) zeros--;
lo++;
}
best = Math.max(best, hi - lo + 1);
}
return best;
}fn solve(bits: &[i64], k: usize) -> usize {
let (mut best, mut lo, mut zeros) = (0usize, 0usize, 0usize);
for hi in 0..bits.len() {
if bits[hi] == 0 { zeros += 1; }
while zeros > k { // too many zeros to flip: shrink
if bits[lo] == 0 { zeros -= 1; }
lo += 1;
}
best = best.max(hi + 1 - lo);
}
best
}import Data.Array
-- Fold carrying (window start, zeros inside, best); the left end is read from an array.
solve :: [Int] -> Int -> Int
solve bits k = third (foldl step (0, 0, 0) (zip [0 ..] bits))
where
arr = listArray (0, length bits - 1) bits
third (_, _, b) = b
step (lo, zeros, best) (hi, b) =
let (lo', z') = shrink lo (zeros + fromEnum (b == 0))
in (lo', z', max best (hi - lo' + 1))
shrink lo z
| z > k = shrink (lo + 1) (z - fromEnum (arr ! lo == 0))
| otherwise = (lo, z)
Variants to try
- Return where to flip: remember the best window; its zeros are the flips.
- Exactly one deletion instead of flips: see the next problem in this module.
Next problems
Longest run of tasks within a time budget
With positive numbers, a run that is over budget only gets worse as it grows, so the left end never moves back.
Open the problem → Medium15 minLongest run of distinct characters
The window that grows on the right and shrinks on the left, and the invariant that makes it correct.
Open the problem → Medium20 minLongest run with at most k distinct letters
The variable window in its plainest form: grow on the right, and while the window breaks the rule, shrink on the left.
Open the problem →Write a solution and run it against the real test table.
Keep going
Longest run of tasks within a time budget
With positive numbers, a run that is over budget only gets worse as it grows, so the left end never moves back.
Open the problem → Medium15 minLongest run of distinct characters
The window that grows on the right and shrinks on the left, and the invariant that makes it correct.
Open the problem → Medium20 minLongest run with at most k distinct letters
The variable window in its plainest form: grow on the right, and while the window breaks the rule, shrink on the left.
Open the problem → Sliding windowThe pattern behind it
A window that grows on the right, shrinks on the left, and holds an invariant at all times.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.