【LeetCode】57. Insert Interval [Interval 系列]
LeetCode中,有很多关于一组interval的问题。大体可分为两类:
1.查看是否有区间重叠; 2.合并重叠区间; 3.插入新的区间; 4. 基于interval的其他问题
【 做题通用的关键步骤】:
1. 按照begin时间排序;
2. 判断两个相邻区间是否重叠:
【假设】
a. 给定的区间是半开区间 [begin, end);
b. 已经按照"begin"排序.
c. 当前的区间是begin, end; 要比较/合并的区间:[ intervals[i][0], intervals[i][1]); (begin <= intervals[i][0])
【重合情况】
(begin == intervals[i][0] || end >= intervals[i][0]) => end = max(end, intervals[i][1])
在做第二类问题时,除了判断是否重叠,还需要合并重叠区间。 只要定义一个[begin, end]代表之前一个区间, 若与当前区间重叠,则更新end
【例题1】 第一类问题示例,Eg. 252. Meeting Rooms (比较简单代码省略)
【例题2】 第二类问题示例, Eg.56. Merge Intervals
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if(intervals.size() == ) return intervals;
vector<vector<int>> res;
sort(intervals.begin(), intervals.end(), [](auto &in1, auto &in2){
return (in1[] < in2[] || (in1[] == in2[] && in1[] > in2[]));
});
auto curr = intervals[];
int i = ;
while(i < intervals.size()) {
if(curr[] < intervals[i][]) {
res.push_back(curr); //无重叠,记录之前的interval;
curr = intervals[i];
}
curr[] = max(curr[], intervals[i][]); // 有重叠更新end
i++;
}
res.push_back(curr);
return res;
}
};
时间复杂度:排序 O(nlogn); 合并 O(n)
------------------------------------------------------------------------------------------------------------------
【例题3】 另一道第二类问题,与string相结合的题目:616. Add Bold Tag in String
Given a string s and a list of strings dict, you need to add a closed pair of bold tag <b> and </b> to wrap the substrings in s that exist in dict. If two such substrings overlap, you need to wrap them together by only one pair of closed bold tag. Also, if two substrings wrapped by bold tags are consecutive, you need to combine them.
其实本质上也是要合并所有在dict里存在并且重叠的子字符串。基本思路是以s中每个字符为起始,找出长度最长的与dict中对应的字符串,如果有这样的字符串,就查看与之前[begin, end]是否重叠。并更新end,或将之前interval输入res中。
string addBoldTag(string s, vector<string>& dict) {
string res = "";
if(s.size() == ) return res;
unordered_map<char, vector<string>> map;
for(auto d: dict){
map[d[]].push_back(d);
}
int begin = , end = -;
for(int i = ; i < s.size(); ++i){
for(auto str: map[s[i]]){
if(i+str.size()- < s.size() && i+(int)str.size()- > end
&& s.substr(i, str.size()) == str){
end = i+str.size()-;
}
}
if(i > end){
if(begin <= end){
string temp = "<b>" + s.substr(begin, end-begin+) + "</b>";
res += temp;
}
res.push_back(s[i]);
begin = i+;
}
}
if(begin <= end){
string temp = "<b>" + s.substr(begin, end-begin+) + "</b>";
res += temp;
}
return res;
}
一些减少时间复杂度的方法,是用一个hash map,根据dict中每一个word首字母为Key, 记录所有以该字母开始的word。在遍历s时,只需查看所有以s[i]起始的字符串即可;另外在确认是否匹配前,可以先查看如果匹配的话,是否会大于当前end (i+word.size()-1 > end)。大于的情况下再去比较两个字符串,以节省时间开销。
--------------------------------------------------------------------------------------------------------------------
【例题4】
第三类题目,注意包含一些边界值需要考虑:57. Insert Interval
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.
这道题目可以用类似的思路,即先排序后遍历,然后对所有overlap的区间进行整合,并插入到合适的位置。因为存在很多情况,所以比较容易出错。
另一种相对不易出错并且时间复杂度少一些的做法:
通过二分查找来找到最后一个比要插入区间小的区间 (intervals[i][1] < begin ),
以及第一个比插入区间大的区间 (intervals[i][0] > end )
然后再对中间部分进行处理
class Solution {
private:
int lastSmall(vector<vector<int>>& intervals, int begin){
int b = , e = intervals.size()-;
while(b < e){
if(e - b == ){
if(intervals[e][] < begin) b = e;
return b;
}
int mid = b + (e-b)/;
if(intervals[mid][] < begin) b = mid;
else e = mid-;
}
return b;
}
int firstBig(vector<vector<int>>& intervals, int end){
int b = , e = intervals.size()-;
while(b < e){
if(e - b == ){
if(intervals[b][] <= end) b = e;
return b;
}
int mid = b + (e-b)/;
if(intervals[mid][] > end) e = mid;
else b = mid+;
}
return b;
}
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
vector<vector<int>> res;
sort(intervals.begin(), intervals.end());
int n = (int)intervals.size();
int begin = newInterval[], end = newInterval[];
int p1 = -, p2 = n;
//p1是最后一个比目标区间小的区间;
//p2是第一个比目标区间搭的区间;
//初始值用来标记不存在符合条件的区间
if(n > && intervals[][] < begin)
p1 = lastSmall(intervals, begin);
if(n > && intervals[n-][] > end)
p2 = firstBig(intervals, end);
if(p1 >= ) res.assign(intervals.begin(), intervals.begin()+p1+);
if(p1+ < n) begin = min(intervals[p1+][], begin);
if(p2- >= ) end = max(intervals[p2-][], end);
res.push_back(vector<int>{begin, end});
if(p2 < n) res.insert(res.end(), intervals.begin()+p2, intervals.end()); return res;
}
};
时间复杂度: 排序 O(nlogn); 寻找目标区间 O(logn)
--------------------------------------------------------------------------------------------------------------------
下面是两道是在区间合并基础上延伸一些的题目
【示例5】 253. Meeting Rooms II
Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference rooms required.
这道题目其实和上边的区间合并思路不太一样。也是要先排序,然后重点是要想清楚在新安排一个会议时,把他安排在之前最早结束的没有重叠的会议室是最优选择。(因为排在他之后的会议都比他开始时间晚,会造成时间的浪费)。
基于此就要知道在安排每个会议时,之前每个会议室结束会议的时间,并且是有序的方便可以更新的。便可想到使用priority_queue
class Solution {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
int n = static_cast<int>(intervals.size());
sort(intervals.begin(), intervals.end(), [](vector<int>& i1, vector<int>& i2){return i1[] < i2[];});
priority_queue<int, vector<int>, greater<int>> pq;
//int num = 0;
for(auto i: intervals) {
int begin = i[];
int end = i[];
if(pq.empty() || pq.top() > begin) pq.push(end);
else {
pq.pop();
pq.push(end);
}
}
return pq.size();
}
};
------------------------------------------------------------------------------------------------------------------
【示例6】 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).
这道题目在insert interval的基础上需要动态的去维护这样一组Intervals。如果还用之前的办法,用一个数组/vector去维护,大量的插入和删除操作会导致很大的时间复杂度。此外要维持有序和查找也要花很多时间。所以用有序map来实现是一个很好的选择。
class RangeModule {
map<int, int> maps; //key: right/end; value: left/begin
public:
RangeModule() { } void addRange(int left, int right) {
auto it = maps.lower_bound(left);
if(it != maps.end()) left = min(left, it->second);
while(it != maps.end() && it->second <= right){
right = max(right, it->first);
auto temp = it;
it++;
maps.erase(temp);
}
maps.insert(make_pair(right, left));
} bool queryRange(int left, int right) {
auto it = maps.upper_bound(left);
return (it != maps.end() && it->first >= right && it->second <= left);
} void removeRange(int left, int right) {
auto it = maps.upper_bound(left);
int l1 = -, r2 = -;
while(it != maps.end() && it->second < right) {
if(it->second < left) {
l1 = it->second;
}
if(it->first > right) {
r2 = it->first;
}
auto temp = it;
it++;
maps.erase(temp);
}
//cout << l1 << ", " << r2 << endl;
if(l1 != -) maps.insert(make_pair(left, l1));
if(r2 != -) maps.insert(make_pair(r2, right));
}
}; /**
* 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);
*/
时间复杂度: O(nlogn); 空间额外开销: O(n) //map
---------------------------------------------------------------------
以上题目均来源:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/meeting-rooms-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
---------------------------------------------------------------------
【LeetCode】57. Insert Interval [Interval 系列]的更多相关文章
- LeetCode: 57. Insert Interval(Hard)
1. 原题链接 https://leetcode.com/problems/insert-interval/description/ 2. 题目要求 该题与上一题的区别在于,插入一个新的interva ...
- Leetcode#57 Insert Interval
原题地址 遍历每个区间intervals[i]: 如果intervals[i]在newInterval的左边,且没有交集,把intervals[i]插入result 如果intervals[i]在ne ...
- [LeetCode] 57. Insert Interval 解决思路
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...
- [leetcode]57. Insert Interval插入区间
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...
- leetCode 57.Insert Interval (插入区间) 解题思路和方法
Insert Interval Given a set of non-overlapping intervals, insert a new interval into the intervals ...
- 第一周 Leetcode 57. Insert Interval (HARD)
Insert interval 题意简述:给定若干个数轴上的闭区间,保证互不重合且有序,要求插入一个新的区间,并返回新的区间集合,保证有序且互不重合. 只想到了一个线性的解法,所有区间端点,只要被其 ...
- [LeetCode] 57. Insert Interval 插入区间
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...
- LeetCode 57. Insert Interval 插入区间 (C++/Java)
题目: Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if nec ...
- leetcode 57 Insert Interval & leetcode 1046 Last Stone Weight & leetcode 1047 Remove All Adjacent Duplicates in String & leetcode 56 Merge Interval
lc57 Insert Interval 仔细分析题目,发现我们只需要处理那些与插入interval重叠的interval即可,换句话说,那些end早于插入start以及start晚于插入end的in ...
- Leetcode 57: Insert Interval 让代码更好读, 更容易测试.
阅读了几个博客, 决定写一个简易版本; 忙着做更多题, 没有时间多考虑优化代码, 所以, 就写一个试试运气. http://blog.csdn.net/kenden23/article/details ...
随机推荐
- IDEA上传图片到tomcat服务器上
前端页面: JS代码: //选中图片 var form = document.getElementById("danxuan"); // 用表单来初始化 var formData ...
- BUAA_2020_OO_第一单元总结
三次作业,三次成长 第一次作业--幂函数求导总结 作业思路和心得 第一次作业的要求只有x的指数这样的幂函数加减组成表达式,对表达式进行求导,而且没有格式错误的检查,所以难度感觉还不是很高.不过由于我寒 ...
- 计算机视觉基本原理——RANSAC
公众号[视觉IMAX]第31篇原创文章 一 前言 对于上一篇文章——一分钟详解「本质矩阵」推导过程中,如何稳健地估计本质矩阵或者基本矩阵呢?正是这篇文章重点介绍的内容. 基本矩阵求解方法主要有: 1) ...
- 大O 表示法
大O表示法 指出了算法有多快.例如,假设列表包含n个元素.简单查找需要检查每个元素,因此需要执行n次操作.使用大O表示法,这个运行时间为O(n).单位秒呢?没有——大O表示法指的并非以秒为单位的速度. ...
- dyld
一.介绍 在 MacOS 和 iOS 上,可执行程序的启动依赖于 xnu 内核进程运作和动态链接加载器 dyld. dyld 全称 the dynamic link editor,即动态链接器,其本质 ...
- centos7中提升用户权限
提升用户权限我看网上资源有两种方法,一种是修改/etc/sudoers/文件将新增的用户权限提升为和root一样的权限,这种方法不知道怎么回事我没用应用成功,这里我介绍第二种方法,第二种方法是更改/e ...
- SQL实战(六)
一. 题目描述 查找排除当前最大.最小salary之后的员工的平均工资avg_salary.CREATE TABLE `salaries` ( `emp_no` int(11) NOT NULL,`s ...
- 对webpack和gulp的理解和区别
webpack是前端构建工具,称为模块打包机,webpack支持模块化:构建前端开发过程中常用的文件,如:js,css,html,img等:使用简单方便,自动化构建.webpack是通过loader( ...
- 详谈XSS防御方法
1.HttpOnly 严格的说,httponly并非为了对抗XSS,它解决的是XSS后的Cookie劫持攻击.Cookie设置了httponly之后,JavaScript读不到该cookie的值. ...
- 【WPF学习】第六十五章 创建无外观控件
用户控件的目标是提供增补控件模板的设计表面,提供一种定义控件的快速方法,代价是失去了将来的灵活性.如果喜欢用户控件的功能,但需要修改使其可视化外观,使用这种方法就有问题了.例如,设想希望使用相同的颜色 ...