2379. Minimum Recolors to Get K Consecutive Black Blocks
Problem Description
You have a string blocks
consisting of characters 'W' (white) and 'B' (black), representing the colors of blocks arranged in a line. Given an integer k
, your goal is to find at least one occurrence of k
consecutive black blocks.
You can perform operations to recolor white blocks to black (but not black to white). The task is to find the minimum number of operations needed to create at least one sequence of k
consecutive black blocks.
For example, if blocks = "WBBWWBBWBW"
and k = 7
, you would need to recolor some white blocks to create 7 consecutive black blocks. The algorithm uses a sliding window approach to find the window of size k
that already contains the most black blocks (or equivalently, the fewest white blocks), as this would require the minimum number of recoloring operations.
The solution counts the number of white blocks ('W') in each window of size k
as it slides through the string. The window with the fewest white blocks represents the optimal position to create k
consecutive black blocks, and the count of white blocks in that window is the answer.
Intuition
To create k
consecutive black blocks, we need to select a contiguous segment of length k
from the string and ensure all blocks in that segment are black. Since we can only recolor white blocks to black, the number of operations needed for any segment equals the number of white blocks in that segment.
The key insight is that we want to minimize the number of operations, which means we should find the segment of length k
that already has the maximum number of black blocks (or equivalently, the minimum number of white blocks). This way, we'll need to recolor the fewest blocks possible.
Instead of checking every possible segment of length k
independently, we can use a sliding window technique. We start by counting the white blocks in the first window of size k
. Then, as we slide the window one position to the right, we only need to:
- Add 1 to our count if the new block entering the window is white
- Subtract 1 from our count if the block leaving the window is white
This allows us to efficiently track the number of white blocks in each window with O(1)
updates rather than recounting the entire window each time. By keeping track of the minimum count across all windows, we find the optimal position that requires the fewest recoloring operations.
The answer is simply the minimum number of white blocks found in any window of size k
, as these are the blocks we need to recolor to achieve k
consecutive black blocks.
Learn more about Sliding Window patterns.
Solution Approach
The solution implements a sliding window approach to efficiently find the minimum number of white blocks in any window of size k
.
Initial Window Setup:
ans = cnt = blocks[:k].count('W')
We start by counting the number of white blocks in the first window (indices 0 to k-1
). This count is stored in both cnt
(current window count) and ans
(minimum count so far).
Sliding the Window:
for i in range(k, len(blocks)):
cnt += blocks[i] == 'W'
cnt -= blocks[i - k] == 'W'
ans = min(ans, cnt)
The loop starts from index k
and goes to the end of the string. For each iteration:
blocks[i]
is the new block entering the window from the rightblocks[i - k]
is the block leaving the window from the left
The window update is done efficiently:
cnt += blocks[i] == 'W'
: If the new block is white, increment the count by 1 (the expressionblocks[i] == 'W'
evaluates toTrue
(1) orFalse
(0))cnt -= blocks[i - k] == 'W'
: If the leaving block is white, decrement the count by 1
After updating the current window's white block count, we update ans
to maintain the minimum count seen so far using ans = min(ans, cnt)
.
Time and Space Complexity:
- Time Complexity:
O(n)
where n is the length of the string, as we visit each character once - Space Complexity:
O(1)
as we only use a constant amount of extra space for variablesans
andcnt
The final answer is the minimum number of white blocks found in any window of size k
, which represents the minimum number of recoloring operations needed.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Example: blocks = "WBWBBBW"
and k = 3
We need to find a window of size 3 that requires the minimum number of recoloring operations to create 3 consecutive black blocks.
Step 1: Initialize the first window (indices 0-2)
- First window:
"WBW"
- Count white blocks: 2 (positions 0 and 2)
- Set
ans = 2
andcnt = 2
Step 2: Slide window to position 1-3
- Window shifts right by 1:
"BWB"
- Block leaving (index 0): 'W' → decrement cnt by 1
- Block entering (index 3): 'B' → no change (not white)
- New
cnt = 2 - 1 + 0 = 1
- Update
ans = min(2, 1) = 1
Step 3: Slide window to position 2-4
- Window:
"WBB"
- Block leaving (index 1): 'B' → no change
- Block entering (index 4): 'B' → no change
- New
cnt = 1 - 0 + 0 = 1
- Update
ans = min(1, 1) = 1
Step 4: Slide window to position 3-5
- Window:
"BBB"
- Block leaving (index 2): 'W' → decrement cnt by 1
- Block entering (index 5): 'B' → no change
- New
cnt = 1 - 1 + 0 = 0
- Update
ans = min(1, 0) = 0
Step 5: Slide window to position 4-6
- Window:
"BBW"
- Block leaving (index 3): 'B' → no change
- Block entering (index 6): 'W' → increment cnt by 1
- New
cnt = 0 - 0 + 1 = 1
- Update
ans = min(0, 1) = 0
Result: The minimum number of operations needed is 0, as we found a window "BBB"
(positions 3-5) that already contains 3 consecutive black blocks.
This example demonstrates how the sliding window efficiently tracks white blocks in each window of size k
, updating the count with O(1) operations as we add/remove elements, ultimately finding the optimal position requiring the fewest recoloring operations.
Solution Implementation
1class Solution:
2 def minimumRecolors(self, blocks: str, k: int) -> int:
3 # Count white blocks in the initial window of size k
4 white_count = blocks[:k].count('W')
5
6 # Initialize minimum recolors needed with the initial window
7 min_recolors = white_count
8
9 # Use sliding window technique to check all windows of size k
10 for i in range(k, len(blocks)):
11 # Add new element to the window (increment if it's white)
12 if blocks[i] == 'W':
13 white_count += 1
14
15 # Remove leftmost element from the window (decrement if it's white)
16 if blocks[i - k] == 'W':
17 white_count -= 1
18
19 # Update minimum recolors needed
20 min_recolors = min(min_recolors, white_count)
21
22 return min_recolors
23
1class Solution {
2 public int minimumRecolors(String blocks, int k) {
3 // Count the number of white blocks in the first window of size k
4 int whiteCount = 0;
5 for (int i = 0; i < k; i++) {
6 if (blocks.charAt(i) == 'W') {
7 whiteCount++;
8 }
9 }
10
11 // Initialize the minimum recolors needed with the first window's white count
12 int minRecolors = whiteCount;
13
14 // Use sliding window technique to check all windows of size k
15 for (int i = k; i < blocks.length(); i++) {
16 // Add the new element entering the window
17 if (blocks.charAt(i) == 'W') {
18 whiteCount++;
19 }
20
21 // Remove the element leaving the window
22 if (blocks.charAt(i - k) == 'W') {
23 whiteCount--;
24 }
25
26 // Update the minimum recolors needed
27 minRecolors = Math.min(minRecolors, whiteCount);
28 }
29
30 return minRecolors;
31 }
32}
33
1class Solution {
2public:
3 int minimumRecolors(string blocks, int k) {
4 // Count white blocks in the initial window of size k
5 int whiteCount = count(blocks.begin(), blocks.begin() + k, 'W');
6
7 // Initialize minimum recolors needed with the initial window
8 int minRecolors = whiteCount;
9
10 // Slide the window through the rest of the string
11 for (int i = k; i < blocks.size(); ++i) {
12 // Add new element to the window (right side)
13 if (blocks[i] == 'W') {
14 whiteCount++;
15 }
16
17 // Remove leftmost element from the window
18 if (blocks[i - k] == 'W') {
19 whiteCount--;
20 }
21
22 // Update minimum recolors if current window has fewer white blocks
23 minRecolors = min(minRecolors, whiteCount);
24 }
25
26 return minRecolors;
27 }
28};
29
1/**
2 * Finds the minimum number of recolors needed to have k consecutive black blocks
3 * @param blocks - String containing 'B' (black) and 'W' (white) blocks
4 * @param k - The desired length of consecutive black blocks
5 * @returns The minimum number of white blocks that need to be recolored to black
6 */
7function minimumRecolors(blocks: string, k: number): number {
8 // Count white blocks in the initial window of size k
9 let whiteCount: number = 0;
10 for (let i = 0; i < k; i++) {
11 if (blocks[i] === 'W') {
12 whiteCount++;
13 }
14 }
15
16 // Initialize the minimum recolors needed with the first window
17 let minRecolors: number = whiteCount;
18
19 // Slide the window through the rest of the string
20 for (let i = k; i < blocks.length; i++) {
21 // Add the new block entering the window
22 if (blocks[i] === 'W') {
23 whiteCount++;
24 }
25
26 // Remove the block leaving the window
27 if (blocks[i - k] === 'W') {
28 whiteCount--;
29 }
30
31 // Update minimum recolors if current window requires fewer
32 minRecolors = Math.min(minRecolors, whiteCount);
33 }
34
35 return minRecolors;
36}
37
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the string blocks
. The algorithm performs an initial count operation on the first k
characters which takes O(k)
time, then iterates through the remaining n - k
characters with constant time operations for each character (checking if a character equals 'W', incrementing/decrementing counter, and updating minimum). Since k ≤ n
, the overall time complexity is O(k) + O(n - k) = O(n)
.
The space complexity is O(1)
. The algorithm only uses a fixed number of variables (ans
, cnt
, and i
) regardless of the input size. The string slicing operation blocks[:k]
creates a temporary substring, but since we're only counting characters and not storing it, and Python's count method operates in constant extra space, the overall space usage remains constant.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Off-by-One Errors in Window Boundaries
A common mistake is incorrectly calculating which element is leaving the window. When at index i
, the element leaving is at index i - k
, not i - k + 1
or i - k - 1
.
Incorrect Example:
# Wrong: Using i - k + 1
for i in range(k, len(blocks)):
cnt += blocks[i] == 'W'
cnt -= blocks[i - k + 1] == 'W' # Error: wrong index
Solution: Remember that if your window ends at index i
, and has size k
, it starts at index i - k + 1
. Therefore, when moving to include blocks[i]
, the element being removed is at blocks[i - k]
.
2. Not Handling Edge Case When k Equals String Length
If k == len(blocks)
, the initial window is the entire string, and the loop doesn't execute at all. This could lead to issues if not properly initialized.
Problematic Pattern:
# If initialization is done incorrectly
ans = float('inf') # Wrong initialization
cnt = 0
for i in range(k, len(blocks)):
# This loop never runs if k == len(blocks)
...
return ans # Returns infinity instead of actual count
Solution: Always initialize ans
with the count from the first valid window:
ans = cnt = blocks[:k].count('W')
3. Using Boolean Addition Incorrectly
While blocks[i] == 'W'
elegantly returns 1 or 0 for True/False, some might try to "optimize" this incorrectly.
Incorrect Example:
# Wrong: Trying to combine operations cnt += (blocks[i] == 'W') - (blocks[i - k] == 'W') # This works but is less readable and more error-prone
Solution: Keep the operations separate for clarity and debugging:
cnt += blocks[i] == 'W' cnt -= blocks[i - k] == 'W'
4. Forgetting to Update the Minimum
It's easy to forget updating the answer variable after adjusting the window count.
Incorrect Example:
for i in range(k, len(blocks)):
cnt += blocks[i] == 'W'
cnt -= blocks[i - k] == 'W'
# Forgot: ans = min(ans, cnt)
return ans # Returns only the initial window's count
Solution: Always update the minimum after each window adjustment:
ans = min(ans, cnt)
5. Misunderstanding the Problem Goal
Some might think we need to find k consecutive blocks that are already black, rather than finding where to create them with minimum operations.
Wrong Interpretation:
# Looking for existing consecutive black blocks
for i in range(len(blocks) - k + 1):
if 'W' not in blocks[i:i+k]:
return 0 # Found k consecutive blacks
Solution: The problem asks for the minimum number of operations (white to black recolors) needed to create k consecutive black blocks anywhere in the string, not to find existing ones.
The three-steps of Depth First Search are:
- Identify states;
- Draw the state-space tree;
- DFS on the state-space tree.
Recommended Readings
https assets algo monster cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in the window The window
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!