LeetCode 715. Range Module / 57. Insert Interval(区间查询更新,离散化)

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;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_26973089/article/details/83692445