题目:
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 numbersleft <= x < right
. 0 < left < right < 10^9
in all calls toaddRange, queryRange, removeRange
.- The total number of calls to
addRange
in a single test case is at most1000
. - The total number of calls to
queryRange
in a single test case is at most5000
. - The total number of calls to
removeRange
in a single test case is at most1000
.
分析:
维护一个区间集合,支持增加和删除区间的操作,当queryRange也就是查询某个区间是否存在时,如果是已有区间包含查询的区间就返回true。
使用一个List用来存储所有的区间,在add方法中保持List中的区间有序。每一次add新区间时,都遍历原来的List,找到待添加区间应插入的位置。
如果原来的区间和插入区间有重叠,就将它们合并。
查询区间可以通过二分法来查找。
程序:
class RangeModule { public RangeModule() { range = new LinkedList<>(); } public void addRange(int left, int right) { List<int[]> tempList = new LinkedList<>(); boolean insert = false; for(int[] r:range){ if(right < r[0] && !insert){ tempList.add(new int[]{left, right}); insert = true; } if(r[0] > right ||r[1] < left) tempList.add(r); else{ left = Math.min(left, r[0]); right = Math.max(right, r[1]); } } if(!insert) tempList.add(new int[]{left, right}); range = tempList; } public boolean queryRange(int left, int right) { int l = 0; int r = range.size()-1; while(l <= r){ int mid = l + (r - l) / 2; int[] p = range.get(mid); if(right < p[0]){ r = mid - 1; }else if(p[1] < left){ l = mid + 1; }else{ return p[0] <= left && p[1] >= right; } } return false; } public void removeRange(int left, int right) { List<int[]> tempList = new LinkedList<>(); for(int[] r:range){ if(r[0] > right || r[1] < left) tempList.add(r); else{ if(r[0] < left) tempList.add(new int[]{r[0], left}); if(r[1] > right) tempList.add(new int[]{right, r[1]}); } } range = tempList; } private List<int[]> range; } /** * Your RangeModule object will be instantiated and called as such: * RangeModule obj = new RangeModule(); * obj.addRange(left,right); * boolean param_2 = obj.queryRange(left,right); * obj.removeRange(left,right); */