A Range Module is a module that tracks ranges of numbers. Your task is to design and implement the following interfaces in an efficient manner.
addRange(int left, int right)
Adds the half-open interval [left, right)
, tracking every real number in that interval. Adding an interval that partially overlaps with currently tracked numbers should add any numbers in the interval [left, right)
that are not already tracked.
queryRange(int left, int right)
Returns true if and only if every real number in the interval [left, right)
is currently being tracked.
removeRange(int left, int right)
Stops tracking every real number currently being tracked in the interval [left, right)
.
Example 1:
addRange(10, 20): null
removeRange(14, 16): null
queryRange(10, 14): true (Every number in [10, 14) is being tracked)
queryRange(13, 15): false (Numbers like 14, 14.03, 14.17 in [13, 15) are not being tracked)
queryRange(16, 17): true (The number 16 in [16, 17) is still being tracked, despite the remove operation)
Note:
A half open interval [left, right)
denotes all real numbers left <= x < right
.
0 < left < right < 10^9
in all calls to addRange, queryRange, removeRange
.
The total number of calls to addRange
in a single test case is at most 1000
.
The total number of calls to queryRange
in a single test case is at most 5000
.
The total number of calls to removeRange
in a single test case is at most 1000
.
解法
一开始想用离散化线段树解决这个问题,后来发现相当的复杂,看了题解之后豁然开朗。思路大概是:用一个map来维护区间,插入删除操作在map上面进行更新。由于不会写,贴下某大神的代码
class RangeModule {
public:
map<int, int> invals;
RangeModule() {}
void addRange(int left, int right) {
auto l = invals.upper_bound(left), r = invals.upper_bound(right);
if (l != invals.begin()) { // find the iterator that is before the new segment
l--;
if (l->second < left) {
l++;
}
}
if (l != r) { // if l != r, we should merge the intervals
left = min(left, l->first);
right = max(right, (--r)->second);
invals.erase(l, ++r);
}
invals[left] = right;
}
bool queryRange(int left, int right) {
auto it = invals.upper_bound(left);
if (it == invals.begin() || (--it)->second < right) {
return false;
}
return true;
}
void removeRange(int left, int right) {
auto l = invals.upper_bound(left), r = invals.upper_bound(right);
if (l != invals.begin()) {
l--;
if (l->second < left) {
l++;
}
}
if (l == r) { // no interval to remove
return;
}
int l1 = min(left, l->first), r1 = max(right, (--r)->second);
invals.erase(l, ++r);
if (l1 < left) { // a smaller interval left in the left
invals[l1] = left;
}
if (r1 > right) { // a smaller interval left in the right
invals[right] = r1;
}
}
};
/**
* Your RangeModule object will be instantiated and called as such:
* RangeModule obj = new RangeModule();
* obj.addRange(left,right);
* bool param_2 = obj.queryRange(left,right);
* obj.removeRange(left,right);
*/
在LeetCode上看到一个更加巧妙的做法, 使用了一个数组来进行。用数组的下标奇偶性判断是区间的left还是right
from bisect import bisect_left as bl, bisect_right as br
class RangeModule:
def __init__(self):
self._X = []
def addRange(self, left, right):
i, j = bl(self._X, left), br(self._X, right)
self._X[i:j] = [left]*(i%2 == 0) + [right]*(j%2 == 0)
def queryRange(self, left, right):
i, j = br(self._X, left), bl(self._X, right)
return i == j and i%2 == 1
def removeRange(self, left, right):
i, j = bl(self._X, left), br(self._X, right)
self._X[i:j] = [left]*(i%2 == 1) + [right]*(j%2 == 1)
def print(self):
print(self._X)
测试一下代码,结果如下。
有了上题这个基础,通过这个数据结构,可以轻松解决57题。
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
You may assume that the intervals were initially sorted according to their start times.
Example 1:
Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]
Example 2:
Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].
class RangeModule {
public:
RangeModule() {}
void addRange(int left, int right) {
auto l = invals.upper_bound(left), r = invals.upper_bound(right);
if (l != invals.begin()) { // find the iterator that is before the new segment
l--;
if (l->second < left) {
l++;
}
}
if (l != r) { // if l != r, we should merge the intervals
left = min(left, l->first);
right = max(right, (--r)->second);
invals.erase(l, ++r);
}
invals[left] = right;
}
bool queryRange(int left, int right) {
auto it = invals.upper_bound(left);
if (it == invals.begin() || (--it)->second < right) {
return false;
}
return true;
}
void removeRange(int left, int right) {
auto l = invals.upper_bound(left), r = invals.upper_bound(right);
if (l != invals.begin()) {
l--;
if (l->second < left) {
l++;
}
}
if (l == r) { // no interval to remove
return;
}
int l1 = min(left, l->first), r1 = max(right, (--r)->second);
invals.erase(l, ++r);
if (l1 < left) { // a smaller interval left in the left
invals[l1] = left;
}
if (r1 > right) { // a smaller interval left in the right
invals[right] = r1;
}
}
map<int, int> invals;
};
class Solution {
public:
vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
RangeModule rangeModule;
for(auto interval: intervals) {
rangeModule.addRange(interval.start, interval.end);
}
rangeModule.addRange(newInterval.start, newInterval.end);
map<int, int>& invals = rangeModule.invals;
vector<Interval> res;
for(auto inval: invals) {
res.push_back(Interval(inval.first, inval.second));
}
return res;
}
};