zoukankan      html  css  js  c++  java
  • [array] leetcode-56. Merge Intervals

    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;
    }
    
  • 相关阅读:
    8.CNN应用于手写字识别
    8.优化器
    6.正则化
    5.Dropout
    4.交叉熵
    3.Minst数据集分类
    2.非线性回归
    1.线性回归
    110. Balanced Binary Tree
    106. Construct Binary Tree from Inorder and Postorder Traversal
  • 原文地址:https://www.cnblogs.com/fanling999/p/7892753.html
Copyright © 2011-2022 走看看