Points That Intersect With Cars
EasyPrompt
You are given a 0-indexed 2D integer array nums representing the coordinates of the cars parking on a number line. For any index i, nums[i] = [starti, endi] where starti is the starting point of the ith car and endi is the ending point of the ith car.
Return the number of integer points on the line that are covered with any part of a car.
Example 1:
Input: nums = [[3,6],[1,5],[4,7]]
Output: 7
Explanation: All the points from 1 to 7 intersect at least one car, therefore the answer would be 7.Example 2:
Input: nums = [[1,3],[5,8]]
Output: 7
Explanation: Points intersecting at least one car are 1, 2, 3, 5, 6, 7, 8. There are a total of 7 points, therefore the answer would be 7.
Constraints:
1 <= nums.length <= 100nums[i].length == 21 <= starti <= endi <= 100
Approaches
3 approaches with complexity analysis and trade-offs.
This is a straightforward brute-force approach. We can use a HashSet data structure to keep track of all the unique integer points that are covered by at least one car. We iterate through each car's interval [start, end] and add every integer point from start to end into the set. Since a HashSet only stores unique elements, any point covered by multiple cars will only be added once. The final answer is simply the total number of elements in the set.
Algorithm
-
- Initialize an empty
HashSet<Integer>to store the unique integer points covered by cars.
- Initialize an empty
-
- Iterate through each car's interval
[start, end]in the inputnumsarray.
- Iterate through each car's interval
-
- For each interval, start a nested loop from
i = starttoi = end.
- For each interval, start a nested loop from
-
- In the nested loop, add the integer
ito theHashSet. The set will automatically handle duplicates.
- In the nested loop, add the integer
-
- After iterating through all the cars and their corresponding points, the total number of unique points is the size of the
HashSet.
- After iterating through all the cars and their corresponding points, the total number of unique points is the size of the
-
- Return the size of the set.
Walkthrough
The algorithm proceeds as follows:
- We initialize a
HashSetof integers, let's call itcoveredPoints, which will store all the unique points covered by cars. - We then loop through each car interval provided in the
numsarray. - For each interval
[start, end], we use a nested loop to iterate through all integer points fromstarttoend, inclusive. - Each of these points is added to our
coveredPointsset. If a point is already in the set, theaddoperation does nothing. - After processing all the intervals, the number of unique covered points is equal to the size of the
coveredPointsset, which we return as the result.
import java.util.HashSet;import java.util.Set; class Solution { public int numberOfPoints(int[][] nums) { Set<Integer> coveredPoints = new HashSet<>(); for (int[] car : nums) { int start = car[0]; int end = car[1]; for (int i = start; i <= end; i++) { coveredPoints.add(i); } } return coveredPoints.size(); }}Complexity
Time
O(N * C), where `N` is the number of cars and `C` is the maximum length of an interval. In the worst case, we iterate through `N` cars, and for each car, we might iterate up to `C` points. Given the constraints `N <= 100` and `C <= 100`, this is feasible.
Space
O(C), where `C` is the maximum possible coordinate value (100 in this case). The `HashSet` can store at most all points from 1 to 100. Since `C` is a constant based on the problem constraints, this can be considered O(1) constant space.
Trade-offs
Pros
The logic is very simple and directly follows the problem description.
It is easy to implement and understand.
Cons
This approach can be inefficient if the range of coordinates is very large, as it iterates through every single point within each interval.
It re-processes points multiple times if they are covered by overlapping intervals, although the
HashSetprevents them from being counted more than once.
Given that the coordinates are constrained to a small range [1, 100], we can optimize the previous approach by replacing the HashSet with a simple boolean array. This array acts as a direct-access map where the index represents the point on the number line. This method avoids the computational overhead associated with hashing.
Algorithm
-
- Create a boolean array,
isCovered, of size 102 (to handle 1-based indexing up to 100), and initialize all its elements tofalse.
- Create a boolean array,
-
- Iterate through each car interval
[start, end]in thenumsarray.
- Iterate through each car interval
-
- For each interval, loop from
point = starttopoint = end.
- For each interval, loop from
-
- Inside this loop, mark the point as covered by setting
isCovered[point] = true.
- Inside this loop, mark the point as covered by setting
-
- After processing all intervals, initialize a counter
countto 0.
- After processing all intervals, initialize a counter
-
- Iterate through the
isCoveredarray from index 1 to 100.
- Iterate through the
-
- If
isCovered[i]istrue, increment thecount.
- If
-
- Return the final
count.
- Return the final
Walkthrough
We can use a boolean array, say isCovered, of size 102 to accommodate all possible coordinates from 1 to 100 (using 1-based indexing). Initially, all entries in this array are false.
We iterate through each car interval [start, end]. For each point i in this range, we set isCovered[i] to true. This effectively marks the point as being covered by at least one car.
After iterating through all the car intervals, we perform a final pass over the isCovered array (from index 1 to 100) and count the number of true values. This count gives us the total number of unique points covered by cars.
class Solution { public int numberOfPoints(int[][] nums) { boolean[] isCovered = new boolean[102]; // Indices 0-101, we use 1-100 for (int[] car : nums) { int start = car[0]; int end = car[1]; for (int i = start; i <= end; i++) { isCovered[i] = true; } } int count = 0; for (int i = 1; i <= 100; i++) { if (isCovered[i]) { count++; } } return count; }}Complexity
Time
O(N * C), where `N` is the number of cars and `C` is the coordinate range. The first phase iterates through all points for all cars, and the second phase iterates through the boolean array once. The total complexity is dominated by the first phase.
Space
O(C), where `C` is the maximum coordinate value (100). We use a boolean array of a fixed size. Based on the problem constraints, this is O(1) constant space.
Trade-offs
Pros
Generally faster in practice than the
HashSetapproach due to direct memory access and better cache locality.It is still simple to implement and understand.
Uses a fixed amount of space determined by the coordinate range.
Cons
This approach is only practical when the range of coordinates is small and known in advance.
It has the same asymptotic time complexity as the HashSet approach and is not suitable for problems with a large coordinate range.
A more scalable and algorithmically efficient approach for interval-based problems is to merge any overlapping intervals. By doing so, we obtain a set of disjoint intervals. The total number of unique points is then the sum of the lengths of these merged, non-overlapping intervals. This method avoids iterating over every single point and is much faster when the coordinate ranges are large.
Algorithm
-
- Sort the
numsarray of intervals based on their start points in ascending order.
- Sort the
-
- If the array is empty, return 0.
-
- Create a new list,
mergedIntervals, and add the first interval from the sorted array to it.
- Create a new list,
-
- Iterate through the rest of the sorted intervals, from the second one onwards.
-
- For each
currentinterval, compare it with thelastinterval inmergedIntervals.
- For each
-
- If the
currentinterval overlaps with thelastone (i.e.,current.start <= last.end), merge them by updating the end of thelastinterval:last.end = max(last.end, current.end).
- If the
-
- If they do not overlap, add the
currentinterval as a new entry tomergedIntervals.
- If they do not overlap, add the
-
- After the merging process is complete, calculate the total number of points by summing the lengths (
end - start + 1) of all intervals inmergedIntervals.
- After the merging process is complete, calculate the total number of points by summing the lengths (
Walkthrough
The key idea is to first sort the intervals based on their starting points. This allows us to process them in an order that makes merging straightforward.
- Sort: We begin by sorting the
numsarray based on the start point of each interval. - Merge: We initialize a list,
mergedIntervals, to store the result of the merge. We add the first interval from our sorted list tomergedIntervals. - We then iterate through the remaining sorted intervals. For each
currentinterval, we look at thelastinterval in ourmergedIntervalslist.- If the
currentinterval overlaps with thelastone (i.e.,current[0] <= last[1]), we merge them by updating the end of thelastinterval to be the maximum of its current end and thecurrentinterval's end. - If there is no overlap, it means we have found a new disjoint interval, so we add the
currentinterval to themergedIntervalslist.
- If the
- Count: Once we have the final list of disjoint merged intervals, we iterate through this list, calculate the length of each interval (
end - start + 1), and sum them up to get the total count of covered points.
import java.util.Arrays;import java.util.Comparator;import java.util.List;import java.util.ArrayList; class Solution { public int numberOfPoints(int[][] nums) { if (nums.length == 0) return 0; Arrays.sort(nums, Comparator.comparingInt(a -> a[0])); List<int[]> merged = new ArrayList<>(); merged.add(nums[0]); for (int i = 1; i < nums.length; i++) { int[] current = nums[i]; int[] last = merged.get(merged.size() - 1); if (current[0] <= last[1]) { // Overlap last[1] = Math.max(last[1], current[1]); } else { // No overlap merged.add(current); } } int totalPoints = 0; for (int[] interval : merged) { totalPoints += (interval[1] - interval[0] + 1); } return totalPoints; }}Complexity
Time
O(N log N), where `N` is the number of cars. The dominant operation is sorting the intervals. The subsequent merging process takes a single pass through the sorted intervals, which is O(N).
Space
O(N) in the worst case. The space complexity of the sorting algorithm in Java for an array of objects is O(N). Additionally, the `mergedIntervals` list can store up to `N` intervals if none of them overlap.
Trade-offs
Pros
This is the most efficient approach with a time complexity of
O(N log N).It is a general solution that works well even if the coordinate range is very large.
Cons
The implementation is more complex than the brute-force approaches.
The sorting step adds an
O(N log N)time cost, which might be slightly slower thanO(N*C)only ifNis very large andCis very small, which is not the case here.
Solutions
Solution
class Solution {public int numberOfPoints(List<List<Integer>> nums) { int[] d = new int[110]; for (var e : nums) { d[e.get(0)]++; d[e.get(1) + 1]--; } int ans = 0, s = 0; for (int x : d) { s += x; if (s > 0) { ans++; } } return ans; }}class Solution {public: int numberOfPoints(vector<vector<int>> &nums) { int d[110]{}; for (auto &e : nums) { d[e[0]]++; d[e[1] + 1]--; } int ans = 0, s = 0; for (int x : d) { s += x; ans += s > 0; } return ans; }};class Solution: def numberOfPoints(self, nums: List[List[int]]) -> int: d = [0] * 110 for a, b in nums: d[a] += 1 d[b + 1] -= 1 return sum(s > 0 for s in accumulate(d))Video 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.