求n個閉區間的所有交集(貪心 線段樹)

2021-09-26 22:48:50 字數 1688 閱讀 6076

問題描述:給你n個閉區間,輸出這n個開區間的所有交區間,可能存在乙個子區間有多次重複,乙個交區間的定義是至少有兩個大區間都包含它,並且答案集中要盡可能地把所有區間合併。注:為了避免歧義,頭對尾交於乙個點則不算交

思路:這是對於力扣986地乙個拓展,如果問題約束到乙個交區間最多只有兩個大區間包含它,那麼就可以先把區間預處理成像力扣986那樣的兩個遞增區間,用雙指標求交集。

對於這個問題我們也是要用到貪心的策略,先對左端點排序,之後維護乙個全域性的最右上限,每次都拿左端點跟這個最右上限比較,大於它就與之前的區間互斥,更新一下上限,否則求一下交。

由於我們已經對左端點排序了,當尋找到一組交地時候,後面如果發現這個左端點在上一組交區間的左邊說明可以合併,於是就把它的右區間拉長,否則就新增新的一組交區間,由於按左端點排序了,當前沒有與前乙個交區間k產生交,後面的區間就更不可能與它產生交了,說明那個交區間已經是最優。這樣實際上就解決了前面的最優子問題,後面照做就能達到全域性最優,符合貪心的套路。

對於這個問題其實還有個更一般的做法,維護乙個線段樹,因為區間問題嘛,最後統計所有的sum大於1的點,用兩個指標掃一次o(n

)o(n)

o(n)

即可,複雜度也是o(n

logn

)o(nlogn)

o(nlog

n),只不過這個做法常數可能會有點大

#include

using

namespace std;

struct interval };

intmain()

);//讀入

sort

(val.

begin()

, val.

end())

;//按左端點排序

if(n)

),r =

max(r, cur_r)

;else

if(cur_r <= r));

}else);

r = cur_r;

//更新全域性右端點}}

for(

int i=

0; isize()

; i++

)printf

("[%d,%d]\n"

, ans[i]

.l, ans[i]

.r);

}return0;

}/*41 5

3 84 7

6 12

*/

對於像leetcode986的交問題實際上是我們這個問題的乙個特例,把所有區間加到乙個陣列後對左端點排序之後和我們這題一樣做也能解決,相當於特殊問題一般化。注意那題相交於一點也算乙個子區間。

class

solution

vectorint>>

intervalintersection

(vectorint>>

& a, vectorint>>

& b)

),r =

max(r, cur_r)

;else

if(cur_r <= r));

}else);

r = cur_r;

//更新全域性右端點}}

return ans;}}

;

遞迴演算法求n個不同字元的所有全排序列

設str是含有n個不同字元的陣列例如12345,perm str,k,n 為str 0 str k 的所有字元全排序輸出函式,n為str陣列字元個數。以此類推,perm str,k 1,n 處理的字元個數比perm str,k,n 處理的字元個數少乙個。假定perm str,k 1,n 可求,對於第...

n個球m個不同的桶每個桶容量有限,求所有放置方法。

每個桶的容量為a1,a2,a3.am 設dp i j 為僅使用第1,2,3.i個桶,放入j個球共有多少種放置方法。設t min,表示第i個桶裡面最多可以放入t個球。當第i個桶放入0,1,2.t個球時,共有dp i 1 j dp i 1 j 1 dp i 1 j t 種放法。得到dp i j dp i...

求從n個陣列任意選取乙個元素的所有組合

最近做專案碰到這個問題,如題從n個陣列任意選取乙個元素的所有組合。比如已知陣列是 1,3 2,4 5 最後組合結果是 1,2,5 1,4,5 3,2,5 3,4,5 網上看了好多帖子,發現寫的太複雜,於是自己動手解決。直接貼解決方案 方法一 執行組合排列的函式 function doexchange...