[Leetcode] 715. Range Module 解题报告

这篇博客详细介绍了如何解决 LeetCode 上的 715. Range Module 问题,探讨了高效实现跟踪数字范围的解题思路与方法,主要涉及 Binary Search Tree 的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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<int, int> invals,用来表示互不相交的线段,例如invales[left] = right就可以表示一个左闭右开的区间[left, right)。下面就看看各个函数分别怎么实现:
    1)addRange(int left, int right):首先找出[left, right)的前一个interval,然后判断我们是否需要在插入interval之前合并已有的interval,如果需要,则首先将待合并的interval删除,并更新left和right,最后将[left, right)插入二分查找树中。该函数的时间复杂度是O(nlogn)。

    2)queryRange(int left, int right):首先找出小于等于[left, right)的一个interval,然后判断它的右边是否覆盖掉了[left, right),如果是,则返回false,否则说明该interval覆盖掉了[left, right),所以返回true。该函数的时间复杂度仍然是O(nlogn)。

    3)removeRange(int left, int right):和addRange类似,我们首先找出和[left, right)重合的interval(s),然后将该区间内的interval(s)都移除掉。但是需要注意的是,如果左边有残余的interval或者右边有残余的interval,则需要分别将它们保留。该函数的时间复杂度仍然是O(nlogn)。

    整个算法的空间复杂度是O(n)。

    代码

    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;
            }
        }
    private:
        map<int, int> invals;
    };
    
    
    /**
     * 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);
     */
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值