LeetCode 56. Merge Intervals

题目大意

给出一个区间集合,合并有交集的区间并返回新集合。

解题思路

思路一

最直观的思路是使用贪心的方法,也就是按照

bool operator()(const Interval &a, const Interval &b) {
    return a.start < b.start || a.start == b.start && a.end >= b.end;
}

的方法对区间进行排序。在有序的条件下,只要对区间进行一次遍历就可以完成合并了;这种方法的复杂度只有 O(nlogn) ,不过数据量很大时STL库中的 sort 函数就开始报 Runtime Error 的错,不知是我的用法有误还是其本身没法处理这么大的数据量;因为不想再写一个排序算法,所以这种思路就此作罢。

思路二

放弃了贪心的方法之后,主要思路就是在数据结构上下功夫。使用了 STL 库中的两个类 unordered_mapvectorunordered_map<int, int> 用来存储区间,将 key 作为区间下界,将 value 作为区间上界;vector<int> 维护有效区间的下界(由有效的键组成的有序序列)。

这两个结构含有数据的重复,本来可以整合到一块儿,不过还是因为懒…

具体的用法是:每插入一个区间[start, end],便从有效区间的下界中找到最接近 start 但不大于 start 的区间起点 s,通过比较这两个区间的关系进行插入操作,更新 unordered_map<int, int>vector<int> 两个结构。

其中查找下界和更新区间的操作是最频繁的,也正是如此才额外开辟了可直接访问的 vector 结构来维护有效区间的下界,这样可以通过二分在 O(logn) 的时间内完成查找;而更新 vector<int> 则使用了插入排序,每次插入的时间复杂度为 O(n)。最坏情况下,每次插入区间都要维护 vector<int> ,这样的时间复杂度为 O(n^2),要高于第一种思路;但事实上,由于区间存在许多重叠,维护的次数远小于查找操作,所以这种方法实际上也不会很慢,就是代码长了些~

源代码

Version 1 - Runtime Error

struct Comp {
    bool operator()(const Interval &a, const Interval &b) {
        return (a.start == b.start && a.end >= b.end) || a.start < b.start;
    }
};

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

        Comp comp;
        sort(intervals.begin(), intervals.end(), comp);

        vector<Interval> res;
        res.push_back(intervals[0]);

        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i].end <= res.back().end) continue;
            else {
                if (intervals[i].start <= res.back().end) {
                    res.back().end = intervals[i].end;
                }
                else {
                    res.push_back(Interval(intervals[i].start, intervals[i].end));
                }
            }
        }

        return res;
    }
}; 

Version 2

/**
 * 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 Intervals {
public:
    Intervals(int start, int end) {
        starts.push_back(start);
        mapping[start] = end;
    }

    void insert(int start, int end) {
        int index = find(start);
        if (index >= 0) {
            int s = starts[index];
            if (mapping[s] >= end) return;
            else if (start <= mapping[s]) {
                mapping[s] = end;
                merge(index);
            }
            else {
                mapping[start] = end;
                starts.push_back(0);
                for (int i = starts.size() - 1; i > index + 1; i--) {
                    starts[i] = starts[i - 1];
                }
                starts[index + 1] = start;
                merge(index + 1);
            }
        }
        else {
            mapping[start] = end;
            starts.push_back(0);
            for (int i = starts.size(); i > 0; i--) {
                starts[i] = starts[i - 1];
            }
            starts[0] = start;
            merge(0);
        }
    }

    int find(int s) {
        if (s < starts[0]) return -1;

        int left, right, mid;
        left = 0; right = starts.size() - 1;

        while (left < right) {
            mid = (left + right) / 2;

            if (starts[mid] == s) return mid;
            else if (starts[mid] > s) {
                right = mid - 1;
            }
            else {
                if (starts[mid + 1] <= s) {
                    left = mid + 1;
                }
                else return mid;
            }
        }

        return left;
    }

    void merge(int index) {
        int target = starts[index];

        while (index + 1 < starts.size() && mapping[target] >= starts[index + 1]) {
            mapping[target] = mapping[target] >= mapping[starts[index + 1]]? mapping[target] : mapping[starts[index + 1]];
            for (int i = index + 1; i < starts.size(); i++) {
                starts[i] = starts[i + 1];
            }
            starts.pop_back();
        }
    }

    void print(vector<Interval> &res) {
        for (int i = 0; i < starts.size(); i++) {
            res.push_back(Interval(starts[i], mapping[starts[i]]));
        }
    }

private:
    unordered_map<int, int> mapping;
    vector<int> starts;
};

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

        Intervals my_intervals(intervals[0].start, intervals[0].end);
        for (int i = 1; i < intervals.size(); i++) {
            my_intervals.insert(intervals[i].start, intervals[i].end);
        }

        vector<Interval> res;
        my_intervals.print(res);

        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值