🧠
Brute Force (Interval List with Full Scan)
💡 Starting with a simple list of intervals helps understand the problem deeply, even though it is inefficient. It shows the core challenges of merging and splitting intervals.
Intuition
Store all intervals in a list. For addRange, merge overlapping intervals by scanning the entire list. For removeRange, split or remove intervals by scanning all intervals. For queryRange, check if the entire query interval is covered by scanning.
Algorithm
- Maintain a list of disjoint intervals sorted by start.
- For addRange(left, right): iterate over intervals, merge overlapping ones with [left, right), and update the list.
- For removeRange(left, right): iterate over intervals, remove or split intervals overlapping with [left, right).
- For queryRange(left, right): check if any interval fully covers [left, right).
💡 The main difficulty is correctly merging and splitting intervals while maintaining a sorted list without overlaps.
class RangeModule:
def __init__(self):
self.intervals = [] # list of [start, end)
def addRange(self, left: int, right: int) -> None:
new_intervals = []
placed = False
for start, end in self.intervals:
if end < left:
new_intervals.append([start, end])
elif start > right:
if not placed:
new_intervals.append([left, right])
placed = True
new_intervals.append([start, end])
else:
left = min(left, start)
right = max(right, end)
if not placed:
new_intervals.append([left, right])
self.intervals = new_intervals
def queryRange(self, left: int, right: int) -> bool:
for start, end in self.intervals:
if start <= left and end >= right:
return True
if start > left:
break
return False
def removeRange(self, left: int, right: int) -> None:
new_intervals = []
for start, end in self.intervals:
if end <= left or start >= right:
new_intervals.append([start, end])
else:
if start < left:
new_intervals.append([start, left])
if end > right:
new_intervals.append([right, end])
self.intervals = new_intervals
# Driver code
rm = RangeModule()
rm.addRange(10, 20)
rm.removeRange(14, 16)
print(rm.queryRange(10, 14)) # True
print(rm.queryRange(13, 15)) # False
print(rm.queryRange(16, 17)) # True
Line Notes
self.intervals = []Initialize empty list to store intervals
for start, end in self.intervals:Iterate over all intervals to merge or split
if end < left:Current interval ends before new range starts, keep as is
if start > right:Current interval starts after new range ends, insert new range if not placed
import java.util.*;
public class RangeModule {
private List<int[]> intervals;
public RangeModule() {
intervals = new ArrayList<>();
}
public void addRange(int left, int right) {
List<int[]> newIntervals = new ArrayList<>();
boolean placed = false;
for (int[] interval : intervals) {
if (interval[1] < left) {
newIntervals.add(interval);
} else if (interval[0] > right) {
if (!placed) {
newIntervals.add(new int[]{left, right});
placed = true;
}
newIntervals.add(interval);
} else {
left = Math.min(left, interval[0]);
right = Math.max(right, interval[1]);
}
}
if (!placed) {
newIntervals.add(new int[]{left, right});
}
intervals = newIntervals;
}
public boolean queryRange(int left, int right) {
for (int[] interval : intervals) {
if (interval[0] <= left && interval[1] >= right) {
return true;
}
if (interval[0] > left) {
break;
}
}
return false;
}
public void removeRange(int left, int right) {
List<int[]> newIntervals = new ArrayList<>();
for (int[] interval : intervals) {
if (interval[1] <= left || interval[0] >= right) {
newIntervals.add(interval);
} else {
if (interval[0] < left) {
newIntervals.add(new int[]{interval[0], left});
}
if (interval[1] > right) {
newIntervals.add(new int[]{right, interval[1]});
}
}
}
intervals = newIntervals;
}
// Main method for testing
public static void main(String[] args) {
RangeModule rm = new RangeModule();
rm.addRange(10, 20);
rm.removeRange(14, 16);
System.out.println(rm.queryRange(10, 14)); // true
System.out.println(rm.queryRange(13, 15)); // false
System.out.println(rm.queryRange(16, 17)); // true
}
}
Line Notes
intervals = new ArrayList<>();Initialize list to store intervals
for (int[] interval : intervals)Iterate all intervals to merge or split
if (interval[1] <= left || interval[0] >= right)Keep intervals that do not overlap removal range
if (!placed)Insert merged interval once after processing overlaps
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class RangeModule {
vector<pair<int,int>> intervals;
public:
RangeModule() {}
void addRange(int left, int right) {
vector<pair<int,int>> newIntervals;
bool placed = false;
for (auto &interval : intervals) {
if (interval.second < left) {
newIntervals.push_back(interval);
} else if (interval.first > right) {
if (!placed) {
newIntervals.push_back({left, right});
placed = true;
}
newIntervals.push_back(interval);
} else {
left = min(left, interval.first);
right = max(right, interval.second);
}
}
if (!placed) {
newIntervals.push_back({left, right});
}
intervals = move(newIntervals);
}
bool queryRange(int left, int right) {
for (auto &interval : intervals) {
if (interval.first <= left && interval.second >= right) {
return true;
}
if (interval.first > left) {
break;
}
}
return false;
}
void removeRange(int left, int right) {
vector<pair<int,int>> newIntervals;
for (auto &interval : intervals) {
if (interval.second <= left || interval.first >= right) {
newIntervals.push_back(interval);
} else {
if (interval.first < left) {
newIntervals.push_back({interval.first, left});
}
if (interval.second > right) {
newIntervals.push_back({right, interval.second});
}
}
}
intervals = move(newIntervals);
}
};
int main() {
RangeModule rm;
rm.addRange(10, 20);
rm.removeRange(14, 16);
cout << boolalpha << rm.queryRange(10, 14) << "\n"; // true
cout << boolalpha << rm.queryRange(13, 15) << "\n"; // false
cout << boolalpha << rm.queryRange(16, 17) << "\n"; // true
return 0;
}
Line Notes
vector<pair<int,int>> intervals;Store intervals as pairs in a vector
for (auto &interval : intervals)Loop over all intervals to merge or split
if (interval.second <= left || interval.first >= right)Keep intervals outside removal range
if (!placed)Add merged interval once after processing overlaps
class RangeModule {
constructor() {
this.intervals = [];
}
addRange(left, right) {
const newIntervals = [];
let placed = false;
for (const [start, end] of this.intervals) {
if (end < left) {
newIntervals.push([start, end]);
} else if (start > right) {
if (!placed) {
newIntervals.push([left, right]);
placed = true;
}
newIntervals.push([start, end]);
} else {
left = Math.min(left, start);
right = Math.max(right, end);
}
}
if (!placed) {
newIntervals.push([left, right]);
}
this.intervals = newIntervals;
}
queryRange(left, right) {
for (const [start, end] of this.intervals) {
if (start <= left && end >= right) {
return true;
}
if (start > left) {
break;
}
}
return false;
}
removeRange(left, right) {
const newIntervals = [];
for (const [start, end] of this.intervals) {
if (end <= left || start >= right) {
newIntervals.push([start, end]);
} else {
if (start < left) {
newIntervals.push([start, left]);
}
if (end > right) {
newIntervals.push([right, end]);
}
}
}
this.intervals = newIntervals;
}
}
// Test
const rm = new RangeModule();
rm.addRange(10, 20);
rm.removeRange(14, 16);
console.log(rm.queryRange(10, 14)); // true
console.log(rm.queryRange(13, 15)); // false
console.log(rm.queryRange(16, 17)); // true
Line Notes
this.intervals = []Initialize empty array to hold intervals
for (const [start, end] of this.intervals)Iterate all intervals to merge or split
if (end <= left || start >= right)Keep intervals outside removal range
if (!placed)Insert merged interval once after processing overlaps
TimeO(n) per operation in worst case due to scanning all intervals
SpaceO(n) to store intervals
Each add/remove/query scans the entire list of intervals, which can grow linearly with number of operations.
💡 For n=1000 operations, this means up to 1000 scans each, totaling up to 1,000,000 operations, which is slow for large inputs.
Interview Verdict: TLE for large inputs, but useful to understand problem basics
This approach is too slow for large inputs but helps grasp interval merging and splitting before optimizing.