1. 程式人生 > >Leetcode 435.無重疊區間

Leetcode 435.無重疊區間

無重疊區間

給定一個區間的集合,找到需要移除區間的最小數量,使剩餘區間互不重疊。

注意:

  1. 可以認為區間的終點總是大於它的起點。
  2. 區間 [1,2] 和 [2,3] 的邊界相互"接觸",但沒有相互重疊。

示例 1:

輸入: [ [1,2], [2,3], [3,4], [1,3] ]

 

輸出: 1

 

解釋: 移除 [1,3] 後,剩下的區間沒有重疊。

示例 2:

輸入: [ [1,2], [1,2], [1,2] ]

 

輸出: 2

 

解釋: 你需要移除兩個 [1,2] 來使剩下的區間沒有重疊。

示例 3:

輸入: [ [1,2], [2,3] ]

 

輸出: 0

 

解釋: 你不需要移除任何區間,因為它們已經是無重疊的了。

 

【題目分析】

這個題目與《演算法導論》中活動安排的題目非常類似。

活動選擇問題
有n個需要在同一天使用同一個教室的活動a1,a2,…,an,教室同一時刻只能由一個活動使用。每個活動ai都有一個開始時間si和結束時間fi 。一旦被選擇後,活動ai就佔據半開時間區間[si,fi)。如果[si,fi]和[sj,fj]互不重疊,ai和aj兩個活動就可以被安排在這一天。該問題就是要安排這些活動使得儘量多的活動能不衝突的舉行。例如下圖所示的活動集合S,其中各項活動按照結束時間單調遞增排序。

   

考慮使用貪心演算法的解法。為了方便,我們用不同顏色的線條代表每個活動,線條的長度就是活動所佔據的時間段,藍色的線條表示我們已經選擇的活動;紅色的線條表示我們沒有選擇的活動。
如果我們每次都選擇開始時間最早的活動,不能得到最優解:

如果我們每次都選擇持續時間最短的活動,不能得到最優解:

 

可以用數學歸納法證明,我們的貪心策略應該是每次選取結束時間最早的活動。直觀上也很好理解,按這種方法選擇相容活動為未安排活動留下儘可能多的時間。這也是把各項活動按照結束時間單調遞增排序的原因。

【思路】

參照上面活動安排的例子,我們很容易得到這個題目的解法。這是一個貪心問題,我們每次都找到那個結束點最小的區間,然後依次向後找那些與前面區間不衝突且結束點早的區間。這個過程中我們把區域性的最優解合併成了全域性的最優解。

 

 1 /**
 2  * Definition for an interval.
 3  * public class Interval {
 4  *     int start;
 5  *     int end;
 6  *     Interval() { start = 0; end = 0; }
 7  *     Interval(int s, int e) { start = s; end = e; }
 8  * }
 9  */
10 public class Solution {
11     public int eraseOverlapIntervals(Interval[] intervals) {
12         if(intervals.length == 0) return 0;
13 
14         Comparator<Interval> comp = new Comparator<Interval>() {
15             public int compare(Interval interval1, Interval interval2) {
16                 if(interval1.end > interval2.end) return 1;
17                 else if(interval1.end < interval2.end) return -1;
18                 else return 0;
19             }
20         };
21 
22         Arrays.sort(intervals, comp);
23         int lastend = intervals[0].end;
24         int remove = 0;
25         for(int i = 1; i < intervals.length; i++) {
26             if(intervals[i].end == lastend) remove++;
27             else if(intervals[i].start < lastend) remove++;
28             else lastend = intervals[i].end;
29         }
30 
31         return remove;
32     }
33 }