leetcode 56. Merge Intervals 题解

随便写写

这道题之前学习数据结构的时候好像就见过
但是印象就不是很深了,如果你直接跑去看答案就会觉得这个题这么简单,但是如果是自己去想的话就可能有各种想法,然后不一定很快能做出来

正文

  • 题目描述
    leetcode 56. Merge Intervals 题解_第1张图片

  • 题目分析
    这个题目目的是让我们将一系列的区间取并集

  • 算法设计及对应的复杂度分析

    • 一开始自己的想法是将区间一个一个的填到一个空集中,这时要考虑的状况非常复杂:

      1. 首先需要遍历所有的区间,检查新插入的区间起点处在什么位置(通过比较待插入区间起点和已有区间集合的起终点);
      2. 找到/没找到之后使用相同的方法查找终点位置;
      3. 此时便可以扩展为一个更大的区间(起点扩展为起点所落在区间的起点,终点扩展为终点所落在区间的终点,如果没有落在某个区间上则无需扩展);
      4. 最后去掉新扩展产生的区间所覆盖的已有区间。

      比如 {【1,3】、【4,5】、【6,8】} 中插入【2,7】,这里首先找到【2,7】的起点2落在【1,3】上;【2,7】的终点7落在【6,8】上;扩展为大区间【1,8】;最后遍历所有现有区间(【1,3】、【4,5】、【6,8】)并去掉其中含在【1,8】当中的,最后将【1,8】加入区间队列。所以合并的结果是【1,8】
      显然按照上面的做法太复杂了:对于每个元素的插入需要遍历两次次result中现有区间,复杂度为O(n),之后有需要遍历一次区间去掉所有被覆盖的区间为O(n),总共插入n个元素,所以这一定是O(n^2)复杂度

    • 所以上面的做法不是很好,而且自己写的代码一直有bug就很烦,所以想着有没有更好的办法,最后发现其实只需要稍微改一下就好:

      1. 我们事先将区间排好序,根据第一个元素大小排序;
      2. 这样每次新插入的区间只可能和当前区间集合的最后一个区间交叉,所以判断前者的start和后者的end即可(前者的start < 后者的end则表明交叉,需要做下一步,否则直接插入该区间即可);

      判断待插入区间的end和当前区间集合最后一个区间的end的大小,取其中大的更新区间集合最后一个区间的末端。
      稍微改了一点之后时间复杂度为O(nln(n)) :c++的sort函数使用的快排复杂度为O(nln(n)),然后是对于每一个插入的元素进行一次比较,是O(n),所以最终的时间复杂度为O(nln(n)),有比较大的提升

  • 代码实现

    class Solution {
    public:
    vector merge(vector& intervals) {
        sort(intervals.begin(), intervals.end(),
            [](Interval a, Interval b){
                return (a.start < b.start);
            }
        );
    
        vector * result = new vector();
        for (auto i = intervals.begin(); i != intervals.end(); i++) {
            if (i != intervals.begin() && result->size() >= 1  && i->start <= (result->end() - 1)->end) {
                (result->end() - 1)->end = ((result->end() - 1)->end) > (i->end) ? (result->end() - 1)->end : i->end;
            } else {
                Interval * temp = new Interval(i->start, i->end);
                result->push_back(*temp);
            }
        }
        return *result;
    }
    };
  • 通过结果

    leetcode 56. Merge Intervals 题解_第2张图片

你可能感兴趣的:(c++)