Maximum White Tiles Covered by a Carpet
MedPrompt
You are given a 2D integer array tiles where tiles[i] = [li, ri] represents that every tile j in the range li <= j <= ri is colored white.
You are also given an integer carpetLen, the length of a single carpet that can be placed anywhere.
Return the maximum number of white tiles that can be covered by the carpet.
Example 1:
Input: tiles = [[1,5],[10,11],[12,18],[20,25],[30,32]], carpetLen = 10
Output: 9
Explanation: Place the carpet starting on tile 10.
It covers 9 white tiles, so we return 9.
Note that there may be other places where the carpet covers 9 white tiles.
It can be shown that the carpet cannot cover more than 9 white tiles.Example 2:
Input: tiles = [[10,11],[1,1]], carpetLen = 2
Output: 2
Explanation: Place the carpet starting on tile 10.
It covers 2 white tiles, so we return 2.
Constraints:
1 <= tiles.length <= 5 * 104tiles[i].length == 21 <= li <= ri <= 1091 <= carpetLen <= 109- The
tilesare non-overlapping.
Approaches
2 approaches with complexity analysis and trade-offs.
A straightforward approach is to test every possible optimal starting position for the carpet. An optimal placement will always have the carpet's start aligned with the start of a tile. If a carpet starts in a gap between tiles, we can slide it rightwards without losing any coverage until it hits the start of the next tile. Therefore, we only need to consider N possible starting positions, where N is the number of tiles.
Algorithm
- Sort the
tilesarray based on their starting positionsl_i. - Initialize a variable
maxCoverageto 0. - Iterate through each tile
ifrom0ton-1, wherenis the number of tiles. - For each
i, consider a carpet starting attiles[i][0]. The carpet's range will be[tiles[i][0], tiles[i][0] + carpetLen - 1]. - Initialize
currentCoverageto 0 for this placement. - Start a nested loop, iterating through each tile
jfromiton-1. - For each tile
j, calculate the number of its white tiles that fall within the carpet's range. - The overlap is calculated as
max(0, min(carpetEnd, tileEnd) - max(carpetStart, tileStart) + 1). - Add this overlap to
currentCoverage. - If a tile
jstarts beyond the carpet's end, we can break the inner loop since the tiles are sorted. - After the inner loop finishes, update
maxCoverage = max(maxCoverage, currentCoverage). - After iterating through all possible start positions, return
maxCoverage.
Walkthrough
The algorithm first sorts the tiles based on their starting positions. This helps to prune the search space in the inner loop. It then iterates through each tile i and considers placing the carpet starting at tiles[i][0]. The carpet will cover the range [tiles[i][0], tiles[i][0] + carpetLen - 1]. For each such placement, it iterates through all subsequent tiles j (from i onwards) to calculate the total number of white tiles covered. For each tile j, it calculates the length of the intersection between the tile's range [tiles[j][0], tiles[j][1]] and the carpet's range. The sum of these intersection lengths gives the total coverage for the current carpet placement. The algorithm keeps track of the maximum coverage found across all possible starting positions.
import java.util.Arrays; class Solution { public int maximumWhiteTiles(int[][] tiles, int carpetLen) { Arrays.sort(tiles, (a, b) -> Integer.compare(a[0], b[0])); int n = tiles.length; int maxCoverage = 0; if (carpetLen == 0) { return 0; } for (int i = 0; i < n; i++) { long carpetStart = tiles[i][0]; long carpetEnd = carpetStart + carpetLen - 1; int currentCoverage = 0; for (int j = i; j < n; j++) { long tileStart = tiles[j][0]; long tileEnd = tiles[j][1]; if (tileStart > carpetEnd) { break; } long overlapStart = Math.max(carpetStart, tileStart); long overlapEnd = Math.min(carpetEnd, tileEnd); if (overlapStart <= overlapEnd) { currentCoverage += (int)(overlapEnd - overlapStart + 1); } } maxCoverage = Math.max(maxCoverage, currentCoverage); } return maxCoverage; }}Complexity
Time
O(N^2), where N is the number of tiles. Sorting takes O(N log N), but it is dominated by the nested loops which take O(N^2) time.
Space
O(log N) or O(N), depending on the space complexity of the sorting algorithm used.
Trade-offs
Pros
Relatively simple to understand and implement.
Cons
The
O(N^2)time complexity makes it too slow for the given constraints, likely resulting in a 'Time Limit Exceeded' error on most platforms.
A more efficient solution uses the sliding window technique. This approach avoids the nested loops of the brute-force method. After sorting the tiles by their start positions, we can iterate through the tiles with a "window" that expands from the right and shrinks from the left. This allows us to find the maximum coverage in a single pass through the tiles, leading to a significantly better time complexity.
Algorithm
- Sort the
tilesarray based on their start positionsl_i. - Initialize two pointers,
i = 0(left) andj = 0(right), to define a sliding window of tiles. Also, initializemaxCover = 0andcurrentCover = 0(sum of lengths of tiles in the window). - Iterate with the right pointer
jfrom0ton-1: a. Add the length oftiles[j]tocurrentCoverto expand the window. b. The span of the current window of tiles[i, j]istiles[j][1] - tiles[i][0] + 1. If this span exceedscarpetLen, the window is too wide. c. Shrink the window from the left: whiletiles[j][1] - tiles[i][0] + 1 > carpetLen, subtract the length oftiles[i]fromcurrentCoverand incrementi. d. After shrinking, the window[i, j]is valid. Now, consider the best placement of the carpet for this window. To maximize coverage, we align the carpet's right end withtiles[j][1]. The carpet starts atcarpetStart = tiles[j][1] - carpetLen + 1. e. This placement might not covertiles[i]fully iftiles[i][0]is less thancarpetStart. Calculate the uncovered part oftiles[i]ascutOff = max(0, carpetStart - tiles[i][0]). f. The total coverage for this configuration iscurrentCover - cutOff. g. UpdatemaxCover = max(maxCover, currentCover - cutOff). - Return
maxCover.
Walkthrough
The algorithm begins by sorting the tiles array based on their start positions. It uses two pointers, i (left) and j (right), to define a "window" of tiles [i, j]. A variable currentCover tracks the sum of the lengths of all tiles currently in the window. The right pointer j iterates from the first to the last tile, expanding the window. For each j, we add the length of tiles[j] to currentCover. The key insight is to consider the optimal carpet placement for the current window [i, j]. To cover as much of tiles[j] as possible, we align the carpet's end with tiles[j][1]. This means the carpet starts at carpetStart = tiles[j][1] - carpetLen + 1. With this carpet placement, the total span of tiles from tiles[i][0] to tiles[j][1] might exceed carpetLen. So, we have a while loop that shrinks the window from the left: as long as the span is greater than carpetLen, we remove tiles[i] from the window (subtracting its length from currentCover) and increment i. After the window is valid, currentCover holds the sum of lengths of tiles from i to j. However, the carpet might not start exactly at tiles[i][0]. It might start later, cutting off a portion of tiles[i]. We calculate this cutOff amount and subtract it from currentCover to get the true coverage for this window configuration. The maximum coverage found across all windows is the answer.
import java.util.Arrays; class Solution { public int maximumWhiteTiles(int[][] tiles, int carpetLen) { Arrays.sort(tiles, (a, b) -> Integer.compare(a[0], b[0])); int n = tiles.length; int maxCover = 0; long currentCover = 0; int i = 0; // Left pointer of the sliding window for (int j = 0; j < n; j++) { // Right pointer of the sliding window currentCover += (long)tiles[j][1] - tiles[j][0] + 1; // Shrink window from the left if its span is wider than the carpet while (i <= j && (long)tiles[j][1] - tiles[i][0] + 1 > carpetLen) { currentCover -= (long)tiles[i][1] - tiles[i][0] + 1; i++; } // At this point, the span of tiles[i..j] is <= carpetLen. // However, the carpet can be placed optimally for this window. // Consider a carpet ending at tiles[j][1]. It starts at tiles[j][1] - carpetLen + 1. // This might cut off a part of the first tile in the window, tiles[i]. long carpetStart = (long)tiles[j][1] - carpetLen + 1; long cutOff = 0; if (tiles[i][0] < carpetStart) { cutOff = carpetStart - tiles[i][0]; } maxCover = Math.max(maxCover, (int)(currentCover - cutOff)); } return maxCover; }}Complexity
Time
O(N log N), where N is the number of tiles. The complexity is dominated by the initial sorting step. The subsequent sliding window traversal is O(N).
Space
O(log N) or O(N) for sorting. The sliding window itself uses O(1) auxiliary space.
Trade-offs
Pros
Highly efficient with a time complexity of O(N log N), which is optimal as sorting is required.
Space-efficient, using only O(1) extra space apart from sorting.
Cons
The logic is more complex than the brute-force approach and requires careful implementation to handle the window shrinking and partial coverage calculation correctly.
Solutions
Solution
class Solution {public int maximumWhiteTiles(int[][] tiles, int carpetLen) { Arrays.sort(tiles, (a, b)->a[0] - b[0]); int n = tiles.length; int s = 0, ans = 0; for (int i = 0, j = 0; i < n; ++i) { while (j < n && tiles[j][1] - tiles[i][0] + 1 <= carpetLen) { s += tiles[j][1] - tiles[j][0] + 1; ++j; } if (j < n && tiles[i][0] + carpetLen > tiles[j][0]) { ans = Math.max(ans, s + tiles[i][0] + carpetLen - tiles[j][0]); } else { ans = Math.max(ans, s); } s -= (tiles[i][1] - tiles[i][0] + 1); } return ans; }}class Solution {public: int maximumWhiteTiles(vector<vector<int>> &tiles, int carpetLen) { sort(tiles.begin(), tiles.end()); int s = 0, ans = 0, n = tiles.size(); for (int i = 0, j = 0; i < n; ++i) { while (j < n && tiles[j][1] - tiles[i][0] + 1 <= carpetLen) { s += tiles[j][1] - tiles[j][0] + 1; ++j; } if (j < n && tiles[i][0] + carpetLen > tiles[j][0]) { ans = max(ans, s + tiles[i][0] + carpetLen - tiles[j][0]); } else { ans = max(ans, s); } s -= (tiles[i][1] - tiles[i][0] + 1); } return ans; }};class Solution: def maximumWhiteTiles(self, tiles: List[List[int]], carpetLen: int) -> int: tiles . sort() n = len(tiles) s = ans = j = 0 for i, (li, ri) in enumerate(tiles): while j < n and tiles[j][1] - li + 1 <= carpetLen: s += tiles[j][1] - tiles[j][0] + 1 j += 1 if j < n and li + carpetLen > tiles[j][0]: ans = max(ans, s + li + carpetLen - tiles[j][0]) else: ans = max(ans, s) s -= ri - li + 1 return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.