Why Intervals Are a Common Problem Pattern in DSA C++ - Performance Analysis
Intervals problems often involve checking or merging overlapping ranges. Understanding their time complexity helps us know how the solution scales as the number of intervals grows.
We want to find out how the number of operations changes when we handle more intervals.
Analyze the time complexity of the following code snippet.
#include <vector>
#include <algorithm>
using namespace std;
vector<pair<int,int>> mergeIntervals(vector<pair<int,int>> &intervals) {
sort(intervals.begin(), intervals.end());
vector<pair<int,int>> merged;
for (auto &interval : intervals) {
if (merged.empty() || merged.back().second < interval.first) {
merged.push_back(interval);
} else {
merged.back().second = max(merged.back().second, interval.second);
}
}
return merged;
}
This code merges overlapping intervals by first sorting them, then combining where needed.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Sorting the intervals and then looping through them once.
- How many times: Sorting takes multiple comparisons (depends on n log n), then one loop runs once over all intervals (n times).
As the number of intervals increases, sorting takes more time, growing faster than just looping.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 * log 10 + 10 ≈ 43 operations |
| 100 | About 100 * log 100 + 100 ≈ 700 operations |
| 1000 | About 1000 * log 1000 + 1000 ≈ 10,000 operations |
Pattern observation: Operations grow a bit faster than the number of intervals because of sorting, but the single loop adds only a small extra cost.
Time Complexity: O(n log n)
This means the time to merge intervals grows a bit faster than the number of intervals because sorting is the main cost.
[X] Wrong: "Merging intervals is just a simple loop, so it must be O(n)."
[OK] Correct: Sorting the intervals first takes more time than just looping, so the overall time is dominated by sorting, not the loop.
Knowing why intervals problems often require sorting helps you explain your approach clearly and shows you understand the cost behind your solution.
"What if the intervals were already sorted? How would the time complexity change?"
Practice
Solution
Step 1: Understand the nature of intervals
Intervals represent ranges, such as time periods or numeric ranges, which appear in many real-world scenarios like scheduling or booking.Step 2: Recognize why intervals are common
Since many problems require handling overlapping or non-overlapping ranges, intervals become a natural pattern to solve these efficiently.Final Answer:
Because many real-world problems involve ranges or periods of time. -> Option AQuick Check:
Intervals model ranges = Because many real-world problems involve ranges or periods of time. [OK]
- Assuming intervals always have fixed lengths
- Thinking intervals never overlap
- Believing intervals are only about sorting
start and end?Solution
Step 1: Identify the correct container for two related integers
A pair holds exactly two values together, suitable for start and end.Step 2: Check syntax correctness
std::pair interval = {start, end}; correctly initializes the pair with start and end.Final Answer:
std::pair interval = {start, end}; -> Option AQuick Check:
Pair holds two ints = std::pair interval = {start, end}; [OK]
- Using vector which can hold many elements, not just two
- Declaring two ints separated by comma incorrectly
- Using map which is for key-value pairs, not intervals
std::vector> intervals = {{1,3}, {2,6}, {8,10}, {15,18}};
std::sort(intervals.begin(), intervals.end());
std::vector> merged;
for (auto &interval : intervals) {
if (merged.empty() || merged.back().second < interval.first) {
merged.push_back(interval);
} else {
merged.back().second = std::max(merged.back().second, interval.second);
}
}
for (auto &i : merged) {
std::cout << "{" << i.first << "," << i.second << "} ";
}Solution
Step 1: Sort intervals by start time
Intervals sorted: {1,3}, {2,6}, {8,10}, {15,18}Step 2: Merge overlapping intervals
{1,3} and {2,6} overlap, merged to {1,6}. Others remain separate.Final Answer:
{1,6} {8,10} {15,18} -> Option CQuick Check:
Merged intervals = {1,6} {8,10} {15,18} [OK]
- Not sorting intervals before merging
- Incorrectly merging non-overlapping intervals
- Printing intervals without merging
std::vector> intervals = {{1,4}, {4,5}};
std::sort(intervals.begin(), intervals.end());
std::vector> merged;
for (auto &interval : intervals) {
if (merged.empty() || merged.back().second <= interval.first) {
merged.push_back(interval);
} else {
merged.back().second = std::max(merged.back().second, interval.second);
}
}Solution
Step 1: Analyze the merging condition
The condition uses merged.back().second <= interval.first, which treats touching intervals as non-overlapping.Step 2: Correct the condition for merging touching intervals
Using '<' instead of '<=' merges intervals that touch at endpoints, which is usually desired.Final Answer:
The condition should use '<' instead of '<=' to merge touching intervals. -> Option BQuick Check:
Use '<' to merge touching intervals = The condition should use '<' instead of '<=' to merge touching intervals. [OK]
- Ignoring touching intervals as overlapping
- Not sorting intervals before merging
- Misusing max function
Solution
Step 1: Sort intervals by start time
Sorting helps process meetings in chronological order.Step 2: Use a min-heap to track earliest ending meeting
Push end times into a min-heap; if a meeting starts after the earliest end, reuse room; else add room.Step 3: Count max simultaneous meetings
The size of the heap at any time is the number of rooms needed.Final Answer:
Sort intervals by start time, use a min-heap to track end times, count max simultaneous meetings. -> Option DQuick Check:
Min rooms = max overlaps tracked by min-heap = Sort intervals by start time, use a min-heap to track end times, count max simultaneous meetings. [OK]
- Merging intervals instead of counting overlaps
- Using stack which doesn't track end times properly
- Ignoring sorting by start time
Ready to prove it?
Pass the test and this pattern moves unknown
