LeetCode 2209 - Minimum White Tiles After Covering With Carpets
The problem presents a binary string floor representing a row of tiles, where '0' corresponds to a black tile and '1' corresponds to a white tile.
Difficulty: 🔴 Hard
Topics: String, Dynamic Programming, Prefix Sum
Solution
Problem Understanding
The problem presents a binary string floor representing a row of tiles, where '0' corresponds to a black tile and '1' corresponds to a white tile. The goal is to cover some of these tiles using a limited number of black carpets of a fixed length, such that the number of white tiles still visible is minimized. You are given numCarpets and carpetLen, representing the number of carpets and their length. Carpets can overlap, which means you can cover the same tiles more than once if necessary, but doing so does not yield extra benefit.
The output is an integer representing the minimum number of white tiles visible after optimally placing the carpets.
Constraints are important here:
1 <= carpetLen <= floor.length <= 1000tells us the input is small enough for dynamic programming approaches but too large for naive brute-force permutation checks of all carpet placements.1 <= numCarpets <= 1000means the number of carpets can be substantial, so any solution must scale in both dimensions: the number of tiles and the number of carpets.floor[i]is'0'or'1', so only two tile types exist, simplifying the counting logic.
Edge cases that could trip up naive implementations include:
- The case where
numCarpets * carpetLen >= floor.length, which could cover the entire floor. - Floors entirely black or white.
carpetLen = 1, which tests minimal coverage granularity.numCarpets = 1, which limits placement choices heavily.
Approaches
The brute-force approach would attempt to place each carpet at every possible position recursively or iteratively, generating all combinations. For each combination, we would count the number of visible white tiles. This approach is correct but computationally infeasible because there are O(floor.length ^ numCarpets) combinations, which quickly becomes astronomically large even for small inputs.
The optimal approach uses dynamic programming (DP). The key observation is that the problem exhibits optimal substructure: the minimum number of white tiles visible for the first i tiles with k carpets depends only on the choices made for the first i-1 tiles.
We define a DP state dp[i][k] as the minimum number of white tiles visible in the first i tiles using up to k carpets. The recurrence relation is:
- If we do not place a carpet ending at tile
i, we add the value of tilei(0 for black, 1 for white) todp[i-1][k]. - If we place a carpet ending at tile
i, we consider the tilei-carpetLenback and take the minimum ofdp[i-carpetLen][k-1]. We cover all tiles in between, so their contribution to white tiles becomes 0.
To implement efficiently, we can use prefix sums to compute the number of white tiles in a range in O(1) time. We also optimize space by using a 2D array dp[i][k] or rolling arrays.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(floor.length^numCarpets) | O(floor.length^numCarpets) | Try every combination of carpet placements; infeasible for large input |
| Dynamic Programming | O(n * numCarpets) | O(n * numCarpets) | DP with prefix sums; efficient and feasible for n <= 1000 |
Algorithm Walkthrough
-
Compute prefix sums of white tiles for the floor string, where
prefix[i]stores the number of white tiles from index0toi-1. -
Initialize a DP table
dpwheredp[i][k]represents the minimum number of white tiles visible for the firstitiles withkcarpets. -
Iterate over tiles
ifrom 1 ton: -
Iterate over
kfrom 0 tonumCarpets:
- If no carpet is placed at
i, setdp[i][k] = dp[i-1][k] + (1 if floor[i-1] == '1' else 0). - If a carpet is placed covering the last
carpetLentiles ending ati, updatedp[i][k] = min(dp[i][k], dp[max(0, i-carpetLen)][k-1]).
- Return
dp[n][numCarpets].
Why it works: The DP ensures that for every prefix of the floor and number of carpets used, we maintain the minimum visible white tiles. By considering both placing a carpet and not placing one, all possibilities are explored efficiently without redundant computation.
Python Solution
class Solution:
def minimumWhiteTiles(self, floor: str, numCarpets: int, carpetLen: int) -> int:
n = len(floor)
# dp[i][k]: min white tiles for first i tiles using up to k carpets
dp = [[float('inf')] * (numCarpets + 1) for _ in range(n + 1)]
dp[0] = [0] * (numCarpets + 1)
for i in range(1, n + 1):
is_white = 1 if floor[i - 1] == '1' else 0
for k in range(numCarpets + 1):
# Option 1: Do not place carpet at this tile
dp[i][k] = dp[i-1][k] + is_white
# Option 2: Place carpet ending at this tile
if k > 0:
dp[i][k] = min(dp[i][k], dp[max(0, i - carpetLen)][k-1])
return dp[n][numCarpets]
Explanation: The outer loop iterates over each tile, and the inner loop over the number of carpets. dp[i][k] is updated either by adding the white tile if uncovered or by covering a segment with a carpet. max(0, i-carpetLen) handles the case where the carpet length exceeds the current prefix.
Go Solution
func minimumWhiteTiles(floor string, numCarpets int, carpetLen int) int {
n := len(floor)
dp := make([][]int, n+1)
for i := range dp {
dp[i] = make([]int, numCarpets+1)
for j := range dp[i] {
dp[i][j] = 1 << 30 // infinity
}
}
for k := 0; k <= numCarpets; k++ {
dp[0][k] = 0
}
for i := 1; i <= n; i++ {
isWhite := 0
if floor[i-1] == '1' {
isWhite = 1
}
for k := 0; k <= numCarpets; k++ {
// Option 1: Do not place carpet
dp[i][k] = dp[i-1][k] + isWhite
// Option 2: Place carpet ending at i
if k > 0 {
prev := i - carpetLen
if prev < 0 {
prev = 0
}
if dp[prev][k-1] < dp[i][k] {
dp[i][k] = dp[prev][k-1]
}
}
}
}
return dp[n][numCarpets]
}
Go Notes: Similar to Python. We use 1 << 30 as infinity. Slice indexing in Go is zero-based, so we adjust i-1 and use max(0, i-carpetLen) equivalent logic.
Worked Examples
Example 1: floor = "10110101", numCarpets = 2, carpetLen = 2
| i | floor[i-1] | k=0 | k=1 | k=2 |
|---|---|---|---|---|
| 1 | 1 | 1 | 0 | 0 |
| 2 | 0 | 1 | 0 | 0 |
| 3 | 1 | 2 | 1 | 0 |
| 4 | 1 | 3 | 1 | 0 |
| 5 | 0 | 3 | 1 | 0 |
| 6 | 1 | 4 | 2 | 0 |
| 7 | 0 | 4 | 2 | 0 |
| 8 | 1 | 5 | 3 | 2 |
Result: 2 white tiles remain.
Example 2: floor = "11111", numCarpets = 2, carpetLen = 3
- Optimal carpet placement covers all tiles; result is
0.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n * numCarpets) | Two nested loops: tiles and number of carpets |
| Space | O(n * numCarpets) | DP table of size (n+1) x (numCarpets+ |