[LeetCode 715] Range Module

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.

 

Solution 1.  Use TreeMap to maintain a sorted set of disjoint intervals. 

Create a tree map. Each entry represents an interval, key is the start number and value is the end number. 

1. queryRange(left, right): find the rightmost entry whose start number is <= left; if existing, check if it covers [left, right - 1];  floorEntry

2. addRange(left, right):  find the rightmost entry e whose start number is <= left; if null or this entry does not intersect with [left, right - 1], i.e: e.getValue() < left, or not adjacent to left, i.e, e.getValue() < left - 1, we need to get the next entry by calling higherEntry on key left to get the first entry that needs to be updated. 

Keep two variables start and end, for each intersecting or adjacent entry, update start and end, remove the current entry then move on to the next higher entry and repeat until there are no ntersecting or adjacent entries. Then insert enrty(start, end) to map.

 

3. removeRange(left, right):  Similar with addRange except that we do not need to check if entries are adjacent to [left, right - 1] anymore. For removal, we only care about intersecting entries. For each intersecting entry e, after removing it from the map, check e.getKey() vs left - 1, right vs e.getValue(). If they still form valid range, insert them back to the map. 

 

 

class RangeModule {
    private TreeMap<Integer, Integer> map;
    public RangeModule() {
        map = new TreeMap<>();
    }
    
    public void addRange(int left, int right) {
        Map.Entry<Integer, Integer> e = map.floorEntry(left);
        int start = left, end = right - 1;
        if(e == null || e.getValue() < left - 1) {
            e = map.higherEntry(left);
        }
        while(e != null && e.getKey() - 1 <= right - 1) {
            Map.Entry<Integer, Integer> next = map.higherEntry(e.getKey());
            start = Math.min(start, e.getKey());
            end = Math.max(end, e.getValue());
            map.remove(e.getKey());
            e = next;
        }
        map.put(start, end);
    }
    
    public boolean queryRange(int left, int right) {
        Map.Entry<Integer, Integer> e = map.floorEntry(left);
        if(e == null) return false;
        return right - 1 <= e.getValue();
    }
    
    public void removeRange(int left, int right) {
        Map.Entry<Integer, Integer> e = map.floorEntry(left);
        if(e == null || e.getValue() < left) {
            e = map.higherEntry(left);
        }
        while(e != null && e.getKey() <= right - 1) {
            Map.Entry<Integer, Integer> next = map.higherEntry(e.getKey());
            int l1 = e.getKey(), r1 = left - 1;
            int l2 = right, r2 = e.getValue();
            map.remove(e.getKey());
            if(l1 <= r1) {
                map.put(l1, r1);
            }
            if(l2 <= r2) {
                map.put(l2, r2);
            }
            e = next;
        } 
    }
}

/**
 * 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);
 */

 

 

 

 

This problem is also tagged as segment tree. But I have not came up with an easy solution that uses segment tree.

 

 
posted @ 2021-02-17 01:45  Review->Improve  阅读(227)  评论(0编辑  收藏  举报