1. 程式人生 > >LeetCode練習題435. Non-overlapping Intervals

LeetCode練習題435. Non-overlapping Intervals

題目

Given a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.

Note:

  1. You may assume the interval's end point is always bigger than its start point.
  2. Intervals like [1,2] and [2,3] have borders "touching" but they don't overlap each other.

Example 1:

Input: [ [1,2], [2,3], [3,4], [1,3] ]

Output: 1

Explanation: [1,3] can be removed and the rest of intervals are non-overlapping.

Example 2:

Input: [ [1,2], [1,2], [1,2] ]

Output: 2

Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping.

Example 3:

Input: [ [1,2], [2,3] ]

Output: 0

Explanation: You don't need to remove any of the intervals since they're already non-overlapping.

分析

原題是讓我們去除有重疊的區間,以使得剩下的區間之間不存在重疊。問最少需要去除多少個這樣的區間。

這道題是典型的用貪心演算法來求解的問題,而難點在於如何找到一個正確的貪心演算法。

我一開始是用以下貪心演算法求解的:每遍歷一次所有的區間,就找出這樣一個區間,與該區間重疊的區間數量最多,然後去除該區間,一直迴圈遍歷重複之前步驟直到剩餘區間沒有重疊的。最後按照該方法計算得到的結果並不正確,所以要憑空找到正確的貪心演算法並不容易。

正確做法如下:

設想這樣的情景:我們要完成一些任務,這些任務都有它自己的完成所需的時間區間,完成任務所需的時間區間有可能重疊,然而我們在一個時間區間內只能執行一個任務。所以為了儘可能的完成更多的任務,我們要選擇執行結束時間更早的任務,這樣在一定的時間區間內,我們才能完成更多的任務。

這道題也類似,我們要選擇結束時間更早的區間,並且這些區間沒有衝突,然後剩餘沒有被選擇的區間就是要被去除的。

通過這道題我們發現,要解決貪心問題,關鍵在於找到一個合適並且正確的貪心演算法,然而有時候查詢這樣的貪心演算法並不容易,這需要我們經過大量的練習積累經驗,這樣才能更好地應對這類貪心問題。

程式碼

/**
 * 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 mySortFun(Interval a, Interval b) {
        if (a.end != b.end) {
            return a.end < b.end;
        }
        else {
            return a.start < b.start;
        }
    }
    //這是一個貪心問題,我們每次都找到那個結束點最小的區間,
    //然後依次向後找那些與前面區間不衝突且結束點早的區間。
    //這個過程中我們把區域性的最優解合併成了全域性的最優解
    int eraseOverlapIntervals(vector<Interval>& intervals) {
        if (intervals.size() <= 1) return 0;
        int head;
        int result = 0;

        sort(intervals.begin(), intervals.end(), mySortFun);

        head = intervals.front().end;
        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i].start < head) {
                result++;
            }
            else {
                head = intervals[i].end;
            }
        }
        return result;
    }
};