版权声明:本文为博主原创文章,博客地址: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);
*/