3111. Minimum Rectangles to Cover Points
Problem Description
You are given a 2D integer array points
, where points[i] = [x_i, y_i]
. You are also given an integer w
. Your task is to cover all the given points with rectangles.
Each rectangle has its lower end at some point (x_1, 0)
and its upper end at some point (x_2, y_2)
, where x_1 <= x_2
, y_2 >= 0
, and the condition x_2 - x_1 <= w
must be satisfied for each rectangle.
A point is considered covered by a rectangle if it lies within or on the boundary of the rectangle.
Return an integer denoting the minimum number of rectangles needed so that each point is covered by at least one rectangle.
Note: A point may be covered by more than one rectangle.
Intuition
To solve this problem, the key observation is that the height of the rectangles does not affect the coverage of points since we are only given a width w
. This allows us to focus solely on the x-coordinates of the points.
-
Sort the Points: Since our goal is to cover all points with the minimum number of rectangles, sorting the points by their x-coordinates helps us efficiently check which points can be covered together.
-
Greedy Approach: We will use a greedy approach to cover the points. After sorting, we will traverse the list from left to right. At each point, we'll use a variable
x1
to keep track of the rightmost x-coordinate that the current rectangle can cover (x1 = -1
initially). -
Check and Cover: As we iterate through the points, if a point's x-coordinate is greater than
x1
, it means the existing rectangle cannot cover it. Thus, we must place a new rectangle, increasing our count by one, and updatex1
to the coordinatex + w
of the current point's x-coordinate.
Through this approach, we can efficiently determine the minimum number of rectangles needed by ensuring we always extend the coverage as far right as possible, which is optimized by starting at the leftmost point and greedily covering additional points with each rectangle.
Solution Approach
The solution uses a greedy strategy combined with sorting to efficiently determine the minimum number of rectangles required to cover all given points. Here is a detailed breakdown of the approach:
-
- The first step is to sort the list of points based on their x-coordinates. Sorting helps in efficiently managing which points can be grouped together under the same rectangle.
- This is performed using the
sort()
function:points.sort()
.
-
Initialization:
- Initialize a counter
ans
to track the number of rectangles used. - Use
x1 = -1
to keep track of the furthest x-coordinate a rectangle can currently cover.
- Initialize a counter
-
Iterative Greedy Process:
- Iterate over each point
(x, _)
in the sorted list:- If the current point's x-coordinate
x
exceedsx1
, it indicates that the current rectangle can no longer cover this point. - In this situation, increase the rectangle count
ans
by 1, and updatex1
tox + w
to represent the furthest point that the new rectangle can cover.
- If the current point's x-coordinate
- Iterate over each point
-
Final Output:
- After processing all points,
ans
will contain the minimum number of rectangles needed to cover all points.
- After processing all points,
The algorithm runs in O(n log n) time complexity due to the initial sort step, where n is the number of points. The subsequent single pass through the points is O(n), making the overall approach efficient. The data structures used are primarily lists, which handle the input points and sorting operation straightforwardly.
Here is the core part of the solution in code form:
points.sort() ans, x1 = 0, -1 for x, _ in points: if x > x1: ans += 1 x1 = x + w return ans
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Consider an example where the points are given as points = [[1, 2], [3, 4], [7, 2], [9, 3]]
, and the width w
is 4. We want to determine the minimum number of rectangles needed to cover these points.
-
Sort the Points:
- First, we sort the points based on their x-coordinates, resulting in
points = [[1, 2], [3, 4], [7, 2], [9, 3]]
.
- First, we sort the points based on their x-coordinates, resulting in
-
Initialization:
- Initialize
ans = 0
to track the number of rectangles used, andx1 = -1
to represent the furthest x-coordinate a rectangle can cover initially.
- Initialize
-
Iterative Greedy Process:
-
Start iterating over the sorted points:
-
First Point (
1, 2
):- The x-coordinate
1
is greater thanx1 (-1)
, which means we need a new rectangle. - Increment
ans
by 1 (ans = 1
). - Update
x1
to1 + 4 = 5
, indicating the furthest this rectangle can cover.
- The x-coordinate
-
Second Point (
3, 4
):- The x-coordinate
3
is less thanx1 (5)
, so it's covered by the current rectangle. No rectangle is added.
- The x-coordinate
-
Third Point (
7, 2
):- The x-coordinate
7
is greater thanx1 (5)
, requiring a new rectangle. - Increment
ans
by 1 (ans = 2
). - Update
x1
to7 + 4 = 11
.
- The x-coordinate
-
Fourth Point (
9, 3
):- The x-coordinate
9
is less thanx1 (11)
, thus it is covered by the current rectangle. No rectangle is added.
- The x-coordinate
-
-
-
Final Output:
- After processing all points, the minimum number of rectangles needed is
ans = 2
.
- After processing all points, the minimum number of rectangles needed is
Thus, the method accurately calculates that two rectangles are necessary to cover all the given points with the specified conditions.
Solution Implementation
1from typing import List
2
3class Solution:
4 def minRectanglesToCoverPoints(self, points: List[List[int]], w: int) -> int:
5 # Sort the list of points based on the x-coordinate
6 points.sort()
7
8 # Initialize the number of rectangles required and the rightmost edge of the last placed rectangle
9 ans = 0
10 x1 = -1 # -1 ensures the first point is always covered
11
12 # Iterate through each point in the sorted list
13 for x, _ in points:
14 # If the current x-coordinate is outside the coverage of the last rectangle
15 if x > x1:
16 ans += 1 # Increment the number of rectangles used
17 x1 = x + w # Update the rightmost edge of the newly placed rectangle
18
19 # Return the total number of rectangles required
20 return ans
21
1import java.util.Arrays;
2
3class Solution {
4 /**
5 * This method calculates the minimum number of rectangles required
6 * to cover all given points on a 2D plane, given a fixed rectangle width `w`.
7 *
8 * @param points An array of integer arrays, where each inner array represents the coordinates [x, y] of a point.
9 * @param w The width of each rectangle.
10 * @return The minimum number of rectangles needed to cover all the points.
11 */
12 public int minRectanglesToCoverPoints(int[][] points, int w) {
13 // Sort the points based on their x-coordinates
14 Arrays.sort(points, (a, b) -> a[0] - b[0]);
15
16 int rectangleCount = 0; // To keep track of the number of rectangles used
17 int currentXLimit = -1; // The rightmost x-coordinate that has been covered so far
18
19 // Iterate over each point
20 for (int[] point : points) {
21 int xCoordinate = point[0]; // Extract the x-coordinate of the current point
22
23 // If the current x-coordinate is greater than the rightmost covered limit,
24 // a new rectangle is needed
25 if (xCoordinate > currentXLimit) {
26 rectangleCount++; // Increment the rectangle count
27 currentXLimit = xCoordinate + w; // Update the covered limit
28 }
29 }
30
31 return rectangleCount; // Return the total number of rectangles needed
32 }
33}
34
1#include <vector>
2#include <algorithm>
3
4class Solution {
5public:
6 // Method to calculate the minimum number of rectangles needed to cover all points
7 int minRectanglesToCoverPoints(std::vector<std::vector<int>>& points, int width) {
8 // Sort points based on their x-coordinates
9 std::sort(points.begin(), points.end());
10
11 // Initialize the number of rectangles to zero
12 int rectanglesCount = 0;
13 // Initialize the rightmost x-coordinate already covered by rectangles to -1
14 int rightmostCoveredX = -1;
15
16 // Iterate over each point
17 for (const auto& point : points) {
18 int xCoordinate = point[0];
19 // If the current point is not covered by the last rectangle
20 if (xCoordinate > rightmostCoveredX) {
21 // Increment the rectangle count to cover this point
22 ++rectanglesCount;
23 // Update the rightmost x-coordinate now covered by the rectangle
24 rightmostCoveredX = xCoordinate + width;
25 }
26 }
27
28 // Return the total number of rectangles used
29 return rectanglesCount;
30 }
31};
32
1// Function to determine the minimum number of rectangles required to cover all points
2function minRectanglesToCoverPoints(points: number[][], w: number): number {
3 // First, sort the points based on the x-coordinate in increasing order
4 points.sort((a, b) => a[0] - b[0]);
5
6 // Initialize the number of rectangles needed and the x-coordinate end limit
7 let ans = 0;
8 let x1 = -1;
9
10 // Iterate over each point
11 for (const [x, _] of points) {
12 // If the current x-coordinate is greater than the current rectangle's end, place a new rectangle
13 if (x > x1) {
14 ans++; // Increment the rectangle counter
15 x1 = x + w; // Update the end limit for the current rectangle
16 }
17 }
18
19 // Return the total number of rectangles used
20 return ans;
21}
22
Time and Space Complexity
The time complexity of the code is O(n \log n)
. This is because the points are sorted at the beginning, which takes O(n \log n)
time, where n
is the number of points. The subsequent loop runs in O(n)
time, iterating through the sorted list of points exactly once, but this does not affect the overall O(n \log n)
complexity due to the dominance of the sorting operation.
The space complexity of the code is O(\log n)
. This arises from the space needed for sorting, where the space complexity is typically O(\log n)
due to the recursive nature of sorting algorithms like Timsort, used in Python.
Learn more about how to find time and space complexity quickly.
What does the following code do?
1def f(arr1, arr2):
2 i, j = 0, 0
3 new_arr = []
4 while i < len(arr1) and j < len(arr2):
5 if arr1[i] < arr2[j]:
6 new_arr.append(arr1[i])
7 i += 1
8 else:
9 new_arr.append(arr2[j])
10 j += 1
11 new_arr.extend(arr1[i:])
12 new_arr.extend(arr2[j:])
13 return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2 int i = 0, j = 0;
3 List<Integer> newArr = new ArrayList<>();
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.add(arr1[i]);
8 i++;
9 } else {
10 newArr.add(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.add(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.add(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
1function f(arr1, arr2) {
2 let i = 0, j = 0;
3 let newArr = [];
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.push(arr1[i]);
8 i++;
9 } else {
10 newArr.push(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.push(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.push(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
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
Want a Structured Path to Master System Design Too? Donโt Miss This!