合并区间-哦吼
思路
大家應該都感覺到了,此題一定要排序,那么按照左邊界排序,還是右邊界排序呢?
都可以!
那么我按照左邊界排序,排序之后局部最優:每次合并都取最大的右邊界,這樣就可以合并更多的區間了,整體最優:合并所有重疊的區間。
局部最優可以推出全局最優,找不出反例,試試貪心。
那有同學問了,本來不就應該合并最大右邊界么,這和貪心有啥關系?
有時候貪心就是常識!哈哈
按照左邊界從小到大排序之后,如果 intervals[i][0] < intervals[i - 1][1] 即intervals[i]左邊界 < intervals[i - 1]右邊界,則一定有重復,因為intervals[i]的左邊界一定是大于等于intervals[i - 1]的左邊界。
即:intervals[i]的左邊界在intervals[i - 1]左邊界和右邊界的范圍內,那么一定有重復!
這么說有點抽象,看圖:(「注意圖中區間都是按照左邊界排序之后了」)
知道如何判斷重復之后,剩下的就是合并了,如何去模擬合并區間呢?
其實就是用合并區間后左邊界和右邊界,作為一個新的區間,加入到result數組里就可以了。如果沒有合并就把原區間加入到result數組。
寫法一
class Solution { public:static bool cmp(vector<int> a,vector<int> b){return a[0]<b[0];}vector<vector<int>> merge(vector<vector<int>>& intervals) {sort(intervals.begin(),intervals.end(),cmp);vector<vector<int>> res;int Maxright=intervals[0][1];int ii=0;for(ii=1;ii<intervals.size();ii++){if(intervals[ii][0]<=Maxright){Maxright=max(intervals[ii][1],intervals[ii-1][1]);intervals[ii][0]=min(intervals[ii-1][0],intervals[ii][0]);intervals[ii][1]=max(intervals[ii-1][1],intervals[ii][1]);}else {res.push_back(intervals[ii-1]);Maxright=intervals[ii][1];}}res.push_back(intervals[ii-1]);return res;} };寫法二
class Solution { public:vector<vector<int>> merge(vector<vector<int>>& intervals) {vector<vector<int>> result;if (intervals.size() == 0) return result;// 排序的參數使用了lamda表達式sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});result.push_back(intervals[0]);for (int i = 1; i < intervals.size(); i++) {if (result.back()[1] >= intervals[i][0]) { // 合并區間result.back()[1] = max(result.back()[1], intervals[i][1]);} else {result.push_back(intervals[i]);}}return result;} };時間復雜度:O(nlogn) ,有一個快排
空間復雜度:O(1),不算result數組(返回值所需容器占的空間)
總結