演算法細節系列(26) 區間

2021-08-01 22:59:56 字數 3314 閱讀 7106

詳細**可以fork下github上leetcode專案,不定期更新。

題目摘自leetcode:

思路:該開始使用了for迴圈中加入了stack的結構,但發現這種思路很難逼近答案。正確的思路應該為:

for
**如下:

public listmerge(listintervals) else

}//合併到一半的區間最後需要統一加上

ans.add(new interval(start,end));

return ans;

}

思路:

可以跟著上一題的思路來,類似於插入排序,找到適當的位置,把newintervals插入到指定位置,在它之前的所有區間可以直接add,與它相交的需要更新interval。**如下:

public listinsert(listintervals, interval newinterval) 

intervals.add(i, newinterval);

int start = intervals.get(target).start;

int end = intervals.get(target).end;

for (int j = target; j < intervals.size(); j++)else

}ans.add(new interval(start,end));

}

還有一種更聰明的做法,在篩選區間時有一定的技巧。

a. intervals[i].end < newinterval.start 可以直接排除

b. intervals[i].start > newinterval.end 可以直接排除

中間區間的更新都是與newinterval有交集,所以更新:

交集中的最小start和交集中的最大end即可

**如下:

public listinsert(listintervals, interval newinterval) 

ans.add(newinterval);

while (i < intervals.size()) ans.add(intervals.get(i++));

return ans;

}

一種樸素的做法,時間複雜度為o(

nlogn)

,可以參考summary range的思路。

思路:

不管三七二十一,把資料全部新增到set集合中來(沒有維護大小關係),惰性做法,當要返回區間時,開始計算,對nums進行排序,連續的值可以合併成乙個區間。

**如下:

public

class

summaryranges

public

void

addnum(int val)

public listgetintervals()

listans = new arraylist<>();

for (int i = 0; i < num.length; i++)

return ans;

}}

這種做法相當糟糕,在加入val時,並沒有維護它的順序,導致每當getintervals為了更好的合併都需要排序一次,這題還可以參考第二題的思路,每當加入乙個元素時,不斷維護該list。時間複雜度可以降到o(

n)。**如下:

public

class

summaryranges

public

void

addnum(int val)

int i = 0;

while (i < ans.size() && newinterval.start > ans.get(i).end + 1) tmp.add(ans.get(i++));

while (i < ans.size() && newinterval.end + 1 >= ans.get(i).start)

tmp.add(newinterval);

while (i < ans.size()) tmp.add(ans.get(i++));

ans = tmp;

}public listgetintervals()

public

static

void

main(string args)

}

上述**的複雜度為o(

n),主要原因在於查詢操作中,需要遍歷ans list,找到合適的兩個斷點,才進行區間更新。

換句話說,我們完全可以在乙個有序的list中進行二分查詢,只需要找到符合:

a. ans.get(i).end + 1 >= newinterval.start

b. ans.get(i).start <= newinterval.end + 1

條件a的查詢很簡單,二分查詢有序list中的end,就能找到待插入的位置i

條件b的查詢可以轉換成:

ans.get(i).start > newinterval.end + 1

因此,也可以二分查詢有序list中的start,能找到終止位置i

但上述**使用了arraylist,實施二分查詢較複雜,但至少給了我們乙個o(log n)的思路。

支援二分查詢,且同時支援o(log n)的插入的資料結構還有tree,所以我們可以實現乙個bst,來做查詢和插入的操作。

如何表達val 和 區間的關係?

treemap這種資料結構能夠完美表達。

構建思路:

就一條,遇到合併的情況,把區間start高的,合併到start低的區間上。

如:[1,1],[2,2] -> [1,2] (刪除第二個區間,修改第乙個區間的end)

**如下:

treemaptree;

public

summaryranges()

public

void

addnum(int val)

else

if (h != null && val == h - 1)

else

if (l != null && tree.get(l).end + 1 >= val)

else

}

查詢,刪除,插入的時間複雜度均為o(

logn

) ,完美的結構。

演算法5 7 區間檢索

間隔搜尋問題給出了一系列的範圍,而測試的時間間隔,尋找和測試間隔交叉間隔。為了解決問題,須要專門編寫乙個類,這個類的介面例如以下 public inte ce intervalst,value 每乙個節點中有兩個值。第乙個值是區間的起點和終點,第二個值是該節點以及子節點中最大的區間終點。為了簡化問題...

7620 區間合併

7620 區間合併 總時間限制 1000ms 記憶體限制 65536kb 描述 給定 n 個閉區間 ai bi 其中i 1,2,n。任意兩個相鄰或相交的閉區間可以合併為乙個閉區間。例如,1 2 和 2 3 可以合併為 1 3 1 3 和 2 4 可以合併為 1 4 但是 1 2 和 3 4 不可以合...

4975 區間翻轉

小q和tangjz正在乙個長度為n的序列a 1,a 2,a n上玩乙個有趣的關於區間翻轉的遊戲。小q和tangjz輪流行動 小q先手。每次行動方玩家需要選擇乙個長度為4x 2或4x 3的區間 l,r 1 l r n 其中x是該玩家自行選擇 的非負整數,然後將a l,a a a r翻轉,例如1 3 2...