[array] leetcode-56. Merge Intervals - Medium

leetcode-56. Merge Intervals - Medium

descrition

Given a collection of intervals, merge all overlapping intervals.

For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

解析

两个思路,都比较有难度。注意算法正确性的证明。

方法 1 - 连通分支

通过的方法来解决。算法描述如下:
以每个间隔 interval 为图的顶点,如果两个 interval 是包含关系,即有其中一个被另一个包含,则使用无向边将两个顶点连接起来。由此图中每一个连通分量都可以进行合并。问题就转换成了如何求图的联通分量的问题。

此方法并非最优解,详细参考官网的 solution。这里重点介绍方法 2.

方法 2

算法描述:

令 ans 结果返回数组,istart, iend 分别表示当前 interval 的起止。

对于 intervals[] 数组:

  • 预处理:根据其起点,即 intervals[i].start 对 intervals 进行非递减有序排序。
  • 初始化:istart = intervals[0].start, iend = intervals[0].end
  • 循环执行以下步骤( i = [1, ..., n-1]):
    • 如果 intervals[i].start <= end:说明当前的 intervals[i] 可以被合并,此时更新 iend = max(iend, intervals[i].end),interval.end 不是有序的,因此要取两段间的最大值最为结尾。
    • 否则:说明当前的 intervals[i] 不能被合并,则 (istart, iend) 形成一个新的被加入到 ans 中,并更新 istart = intervals[i].start, iend = intervals[i].end
  • 注意最后一次 (istart, iend) 加入到 ans 中。

正确性证明:

使用反证法进行证明。

假设:以上算法不能将某些本应被合并的 interval 进行合并。

根据假设,则说明存在以下情况: 3 个下标,i, j, k,不失一般性令 i < j < k,此时 intervals[i] 和 intervals[k] 可以合并,但 intervals[i] 和 intervals[j],intervals[j] 和 intervals[k] 都不能合并。(算法中只考虑了相邻的 interval,因此当该情况存在时不能被识别)。

由以上假设可以得到不等式:

由不能合并的条件得到:
intervals[i].end < intervals[j].start
intervals[j].end < intervals[k].start
由合并的条件得到:
intervals[i].end >= intervals[k].start

根据 interval 的定义,有 intervals[j].start <= intervals[j].end,由此对以上不等式进行合并得到:

intervals[i].end < intervals[j].start <= intervals[j].end < intervals[k].start
==> intervals[i].end < intervals[k].start
与条件 intervals[i].end >= intervals[k].start 矛盾。

综上,算法得到的结果是正确的。

复杂度分析

  • 时间复杂度-O(nlog(n)),取决于排序算法
  • 空间复杂度-O(1) 或 O(n),取决于排序算法是否可以原址完成。

code

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Interval{
	int start;
	int end;
	Interval(): start(0), end(0) {}
	Interval(int s, int e): start(s), end(e) {}
};

class Solution{
public:
	vector<Interval> merge(vector<Interval>& intervals){
		vector<Interval> ans;
		if(intervals.empty())
			return ans;

		// sort intervals in ascending by Interval.start
		sort(intervals.begin(), intervals.end(), comp);

		int istart = intervals[0].start; // the start of the current interval
		int iend = intervals[0].end;     // the end of the current interval
		for(int i=1; i<intervals.size(); i++){
			if(intervals[i].start <= iend){
				iend = max(iend, intervals[i].end); 
			}else{
				ans.push_back(Interval(istart, iend));
				istart = intervals[i].start;
				iend = intervals[i].end;
			}
		}

		// don't forget the last interval
		ans.push_back(Interval(istart, iend));

		return ans;
	}

	static bool comp(Interval int1, Interval int2){ // in ascending
		return int1.start < int2.start;
	}
};

int main()
{
	return 0;
}
posted @ 2017-11-24 23:33  .....?  阅读(361)  评论(0编辑  收藏  举报