Minimum Number of K Consecutive Bit Flips is a classic greedy problem. The naive simulation is too slow, but a single left-to-right sweep with a difference array turns it into clean O(n) — and it teaches the trick of tracking flip parity instead of actually flipping bits.
Problem. You are given a binary array nums and an integer k. In one operation you choose any
contiguous window of exactly k bits and flip every bit in it (0 to 1, 1 to 0). Return the minimum
number of operations to make the whole array all 1s, or -1 if it is impossible.
Example: nums = [0, 1, 0], k = 2 to answer 2 (flip the window [0, 2), then the window [1, 3)).
The slow way first
The obvious idea: scan left to right, and whenever you see a 0, flip the window of k bits starting there. That greedy choice is correct, but if you actually flip every bit in the window each time, one operation costs O(k), so the whole thing is O(n·k) — too slow when both are large.
The question to ask: do I really need to flip the bits, or just know the result? All I care about at position i is the bit's current value after every earlier flip. If I can compute that in O(1), I never touch the window contents at all.
The idea: track flip parity with a difference array
Each flip window only matters as parity — an even number of flips covering a position cancels out, an odd number flips it. So keep a running parity. The effective bit at i is nums[i] XOR parity.
When a flip starts at i, toggle parity and record that this flip ends at i + k by marking diff[i + k]. As the sweep reaches each index, first apply any pending expirations (parity ^= diff[i]) so windows automatically stop covering once they run out.
Greedy correctness: the leftmost effective 0 can only be fixed by a window that starts at i (any earlier start is already past, any later start cannot reach back). So that flip is forced — no choice, no backtracking.
Walk through it
Step through the animation. The pointer i scans left to right. The parity label tracks the running flip count mod 2. At i = 0 the effective bit is 0, so we flip [0, 2). At i = 1 parity is still 1, the effective bit is again 0, so we flip [1, 3). At i = 2 the first window expires (diff[2]), parity returns to 1, the effective bit is 1, and we are done with 2 flips.
Pseudocode
diff = array of zeros, length n + 1 # diff[j] marks a flip window ending at j
flips = 0
parity = 0
for i from 0 to n - 1:
parity ^= diff[i] # expire any window that ended here
if (nums[i] XOR parity) == 0: # effective bit is 0 -> must fix it
if i + k > n:
return -1 # window would run off the end
flips += 1
parity ^= 1 # this flip now covers forward
diff[i + k] ^= 1 # ...until index i + k
return flipsThe Python solution
def min_k_bit_flips(nums, k):
n = len(nums)
diff = [0] * (n + 1)
flips = parity = 0
for i in range(n):
parity ^= diff[i]
if (nums[i] ^ parity) == 0:
if i + k > n:
return -1
flips += 1
parity ^= 1
diff[i + k] ^= 1
return flipsdiffis the difference array:diff[j] = 1means a flip window ends just before indexj.parity ^= diff[i]refreshes the running parity by expiring any window that ended ati.nums[i] ^ parityis the effective bit — the real value after all flips so far, computed in O(1).- If that effective bit is 0, we are forced to flip here.
i + k > nmeans the window spills past the end, which is impossible, so we return-1. - Flipping is recorded, not performed: toggle
paritynow anddiff[i + k]so the window auto-expires later.
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (flip each window) | O(n·k) (moderate) | every op touches k bits |
| Difference array (this solution) | O(n) (moderate) | one pass, O(1) per index |
O(n) (moderate)We trade O(n) extra space (the diff array) for the speed win: O(n·k) to O(n). The diff array can be replaced by a sliding-window counter for O(1) space, but the parity idea is the same.
When this pattern shows up
Whenever a problem applies range updates while you sweep — flip a window, add to a window, mark an interval — reach for a difference array. You record the effect at the window edges and accumulate it as you scan, turning per-window O(k) work into O(1).
The greedy only works because you process strictly left to right and the leftmost 0 has exactly one
legal flip. Do not reorder the scan, and remember to check i + k > n before flipping — that bounds
check is the only thing that detects the impossible case.
Practice
For nums = [0, 1, 0], k = 2, at i = 1 the running parity is 1. What is the effective bit, and what do we do?
1. Why track parity instead of actually flipping the bits in each window?
2. What does diff[i + k] record when we flip a window starting at i?
3. Why is flipping the leftmost effective 0 always the correct greedy move?
4. When does the algorithm return -1?