Leetcode 435.無重疊區間
無重疊區間
給定一個區間的集合,找到需要移除區間的最小數量,使剩餘區間互不重疊。
注意:
- 可以認為區間的終點總是大於它的起點。
- 區間 [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 }