LeetCode Range模块

版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89600356

Range 模块是跟踪数字范围的模块。你的任务是以一种有效的方式设计和实现以下接口。

addRange(int left, int right) 添加半开区间 [left, right),跟踪该区间中的每个实数。添加与当前跟踪的数字部分重叠的区间时,应当添加在区间 [left, right) 中尚未跟踪的任何数字到该区间中。
queryRange(int left, int right) 只有在当前正在跟踪区间 [left, right) 中的每一个实数时,才返回 true。
removeRange(int left, int right) 停止跟踪区间 [left, right) 中当前正在跟踪的每个实数。

示例:

addRange(10, 20): null
removeRange(14, 16): null
queryRange(10, 14): true (区间 [10, 14) 中的每个数都正在被跟踪)
queryRange(13, 15): false (未跟踪区间 [13, 15) 中像 14, 14.03, 14.17 这样的数字)
queryRange(16, 17): true (尽管执行了删除操作,区间 [16, 17) 中的数字 16 仍然会被跟踪)

提示:

半开区间 [left, right) 表示所有满足 left <= x < right 的实数。
对 addRange, queryRange, removeRange 的所有调用中 0 < left < right < 10^9。
在单个测试用例中,对 addRange 的调用总数不超过 1000 次。
在单个测试用例中,对  queryRange 的调用总数不超过 5000 次。
在单个测试用例中,对 removeRange 的调用总数不超过 1000 次。

思路分析: 这道题有点类似于区间的合并、删除问题。
LeetCode 合并区间
LeetCode 插入区间
addRange相当于插入并合并区间,removeRange只要删除在此范围之间的即可,queryRange如果找到了没有出现的元素直接返回false。不过细节问题还是有点复杂的,需要严密的逻辑和清晰的思路。

class RangeModule {
public:
	list<pair<int, int>> myList;//按照递增的顺序存储所有不重叠的Range模块
	RangeModule() {

	}
    //添加Range
	void addRange(int left, int right) {
		auto it = myList.begin();
        //第一步:确定[left,right - 1]插入的位置(第一个与它有交集的元素)
		while (it != myList.end() && it->second < left) {
			++it;
		}
        //第二步:判断是插入到list中还是修改list
        //如果是插入尾端、或者两个Range之间(list中没有Range与它有交集),直接插入
		if (it == myList.end() || it->first > right - 1) {
			myList.insert(it, { left, right - 1 });
		}
		else {
            //此时修改it指向的元素
			it->first = min(it->first, left);
			it->second = max(it->second, right - 1);
            //然后看it后面是否有需要合并的Rande
			auto beforeIt = it++;
			while (it != myList.end() && beforeIt->second >= it->first) {
				beforeIt->second = max(it->second, beforeIt->second);
				it = myList.erase(it);
			}
		}
	}
    //查询Range
	bool queryRange(int left, int right) {
		auto it = myList.begin();
        //第一步:确定第一个与[left,right - 1]有交集元素的位置
		while (it != myList.end() && it->second < left) {
			++it;
		}
		if (it == myList.end()) {
			return false;
		}
        //第二步:开始判断[left, right - 1]中的每个元素是否都在list中
		while (it != myList.end() && left < right) {
			if (left > it->second) {
                //如果当前[left, right - 1]在it的后面
				++it;
			}
			else if (left >= it->first){
                //已经找到了一部分,更新left
				left = it->second + 1;
			}
			else {
				break;
			}
		}
		return left >= right;
	}
    //删除Range
	void removeRange(int left, int right) {
		auto it = myList.begin();
        //第一步:确定第一个与[left,right - 1]有交集元素的位置
		while (it != myList.end() && it->second < left) {
			++it;
		}
        //特殊情况,没有元素与[left,right - 1]有交集
		if (it == myList.end() || it->first >= right) {
			return;
		}
        //第二步:开始删除[left,right - 1]中的Range
		while (left != right && it != myList.end()) {
            if (it->first >= right) {//已经删除完毕
				return;
			}
			else if (it->first >= left) {
				if (right - 1 >= it->second) {
                    //当前it是[left,right - 1]中的子Range,全部删除
					left = it->second + 1;//更新left
					it = myList.erase(it);
				}
				else {
                    //当前it前半部分是[left,right - 1]中的右半部分
					it->first = right;//修改it的左边界即可
					return;
				}
			}
			else if (it->second > right - 1) {
                //当前[left,right - 1]是当前it指向的Range的子部分
                //将it中的[left,right - 1]部分挖去,得到[it->first, left - 1], [right, it->second]
				it = myList.insert(it, { it->first, left - 1 });
				++it;
				it->first = right;
				return;
			}
			else {
                //当前it的右半部分是[left,right - 1]是左半部分
				int tempLeft = it->second + 1;
				it->second = left - 1;//修改it的右边界
				left = tempLeft;//更新left
                ++it;
			}
		}
	}
};


/**

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

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/89600356