赞
踩
题目:
给一个区间数组,删除最小个数的、被覆盖的区间,返回最终删除覆盖区间后剩余的区间个数。对于区间[a,b)和[c,d)当且仅当c>=a且d<=b的时候,a-b完全覆盖c-d
区间算法解决的重点:
1、升序排列,定出区间之间左端点的关系,只需使用右端点即可得到区间关系,简化操作
2、区间关系有三种:
解题思路:
!注意:在这个题目中,由于升序排列区间之后,能产生覆盖只可能在相邻的区间中产生覆盖,因此,只需要用left和right记录此时最邻近的、已覆盖的最大区间,由此判断下一个区间是否会产生完全覆盖
小坑记录:
bool比较函数传入sort方法的时候,请用static定义
代码如下:
- class Solution {
- public:
- static bool compare(const vector<int>&a,const vector<int>&b){
- if(a[0]<b[0]) return true;
- else if(a[0]==b[0] && a[1]<b[1]) return true;
- else return false;
- }
- int removeCoveredIntervals(vector<vector<int>>& intervals) {
- //升序排列
- sort(intervals.begin(),intervals.end(),compare);
- //只有当完全被覆盖的时候删除
- //只需要记录left和right即当前已存在的最大区间的左右边界
- //由于本身就是升序排列的,那么,当遇到断开的不交集新区间,重新赋值left、right即可,因为区间升序排列,只可能在邻近区间操作
-
-
- int left=intervals[0][0],right=intervals[0][1];
- int count=intervals.size();
- for(int i=1;i<intervals.size();i++){
- cout<<left<<" "<<right<<endl;
- //区间关系分为三种情况:
- //1、完全覆盖
- //2、有交集,合并为大区间
- //3、无交集,更新为新区间
- if(intervals[i][0]>=left && intervals[i][1]<=right){
- count--;
- }
- else if(right>=intervals[i][0] && right<=intervals[i][1]){
- //注意,这里之所以不考虑left的关系,是因为left必然小于等于新遍历到的区间->这就是升序排列控制的性质
- right=intervals[i][1];
- }
- else{
- left=intervals[i][0];
- right=intervals[i][1];
- }
-
- }
- return count;
- }
- };
-
题目:将区间合并为不相交区间列表
按照上面所说的区间关系,记录left和right,不断更新
在断开区间的时候或者在遍历末尾,将新纪录的区间放入
- class Solution {
- public:
- static bool compare(const vector<int> & a,const vector<int> &b){
- if(a[0]<b[0]) return true;
- else if(a[0]==b[0] && a[1]<b[1]) return true;
- else return false;
- }
- vector<vector<int>> merge(vector<vector<int>>& intervals) {
- vector<vector<int>> mergeInterval;
- //排序
- sort(intervals.begin(),intervals.end(),compare);
-
- int left=intervals[0][0],right=intervals[0][1];
- for(int i=1;i<intervals.size();i++){
- //部分覆盖
- if(right>=intervals[i][0] && right<=intervals[i][1]) right=intervals[i][1];
- else if(right<intervals[i][0]){//没有交集
- //刷新,存入区间
- vector<int> qujian;
- qujian.push_back(left);
- qujian.push_back(right);
- mergeInterval.push_back(qujian);
- //更新left 和 right
- left=intervals[i][0];
- right=intervals[i][1];
- }
- }
-
- //最后,记录下来的合并区间,最新的,还没来得及放入到数组中,最后继续放入
- vector<int> qujian;
- qujian.push_back(left);
- qujian.push_back(right);
- mergeInterval.push_back(qujian);
-
-
- return mergeInterval;
- }
- };
题目:两个不相交的、已升序排列的区间列表,求出两个区间列表之间存在的相交区间集合(集合左闭右闭)
解题思路:
1、双指针法,根据升序、不相交的特性,每次对比,移动具有更小右值的区间列表的指针【这样的移动可能会带来又一次相交】
2、计算相交区间
上面讨论了区间有三种宏观上的关系,除了不相交以外,都可以归为相交情况。但是相交区间要求具体的相交范围,可以总结为以下4种可能性
相交区间的关系:
对于区间[a1,b1]和[a2,b2]
总结下来如下图所示:
由上述规律总结,对于两个区间的交集部分,设为[c1,c2]
c1=max(a1,a2). c2=min(b1,b2)
代码如下:
-
- class Solution {
- public:
- vector<vector<int>> intervalIntersection(vector<vector<int>>& firstList, vector<vector<int>>& secondList) {
- vector<vector<int>> res;
- int len1=firstList.size(),len2=secondList.size();
- //特殊情况,两个区间列表一样没有交集
- if(!len1 || !len2 || firstList[len1-1][1]<secondList[0][0] || secondList[len2-1][1]<firstList[0][0]) return res;
-
- //双指针法
- int j=0,i=0;
- while(i<len1 && j<len2){
- //如果不是完全不相交
- if(!(firstList[i][0]>secondList[j][1] || firstList[i][1]<secondList[j][0])) {
- vector<int> seq;
- //相交的区间有四种情况,总结来就是取边界
- int left=max(firstList[i][0],secondList[j][0]);
- int right=min(firstList[i][1],secondList[j][1]);
-
- seq.push_back(left);
- seq.push_back(right);
-
- res.push_back(seq);
-
- }
-
- //注意:每个区间列表中都是升序、不相交的;所以下一个区间的左值一定大于上一个区间的有值
- //所以还可能继续被交的【即右值范围更大的留着】,另一个的列表指针移动
-
- if(firstList[i][1]<secondList[j][1]){
- i++;
- }
- else j++;
- }
- return res;
-
- }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。