Non-overlapping Intervals 无重叠区间

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

  1. 可以认为区间的终点总是大于它的起点。
  2. 区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:

输入: [ [1,2], [2,3], [3,4], [1,3] ]

输出: 1

解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

输入: [ [1,2], [1,2], [1,2] ]

输出: 2

解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

输入: [ [1,2], [2,3] ]

输出: 0

解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

思路:这道题先说解法,首先按照结束时间排序,然后遍历数组,先把第一个元素加进答案中,然后遍历后面的元素,如果后面元素的起始时间和截止时间包含第一个元素,就跳过。否则就把元素加入答案。伪代码如下:

Sort jobs by finish times so that f1 <= f2 <= ... <= fn.
select a task ——>A 
for j = 1 to n {
   if (job j compatible with A)
      A and {j} ——> A
}
return A

其实贪心算法如果简单的题好理解(比如01背包问题),但是对于这类直接给出结论的确实让人难以理解,为什么那么多种其他组合,这种解法就能得到最优解呢?下面给出证明:

首先,该算法选出的区间是互不重叠的。

 其次,设fi为该算法所接受的第i个区间的右端点坐标,gi为某最优解中的第i个区间的右端点坐标。

命题1.1 当i>=1时,该算法所接受的第i个区间的右端点坐标fi<=某最优解中的第i个区间的右端点坐标gi。

该命题可以运用数学归纳法来证明。对于i=1,命题显然为真,因为算法第一个选择的区间拥有最小右端点坐标。令i>1,假定论断对i-1为真,即fi-1<=gi-1。则最优解的第i个可选区间所组成的集合包含于执行该算法时第i个可选区间所组成的集合;而当算法选择第i个区间时,选的是在可选区间中右端点坐标最小的一个(意思就是说对于最优解而言,第i个区间可以选择的区间是一个集合,不只一个,而该算法选择的是右边结束时间最少的那个区间(集合中的区间的其中一个),),所以有fi<=gi。证毕。

设该算法选出了k个区间,而最优解选出了m个区间。

命题1.2  最优解选出的区间数量m=该算法选出的区间数量k。

假设m>k,根据命题1.1,有fk<=gk。由于m>k,必然存在某区间,在gk之后开始,故也在fk之后开始。而该算法一定不会在选了第k个区间后停止,还会选择更多的区间,产生矛盾。所以m<=k,又因为m是最优解选出区间个数,所以m>=k。,因而m=k.

综上所述,算法选出的区间是最优解。

参考代码:

/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
class Solution {
public:
    static bool mycmp(const Interval &a, const Interval &b) {
	    return a.end < b.end;
    }
    int eraseOverlapIntervals(vector<Interval>& intervals) {
	if (intervals.size() == 0) return 0;
	int count=1;
	sort(intervals.begin(), intervals.end(), mycmp);
	Interval lastInterval=intervals[0];
	for (int i = 1; i < intervals.size(); i++) {
		if (intervals[i].start < lastInterval.end && lastInterval.end <= intervals[i].end) continue;
		else lastInterval = intervals[i], count++;
	}
	return intervals.size() - count;        
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值