O 1 時間複雜度來獲得佇列或棧的最大值或者最小值

2021-10-17 03:43:14 字數 3741 閱讀 8206

(1)

o(1)

o(1)

,所以很容易想到用空間換取時間的思路。

(一) 劍指 offer 30. 包含min函式的棧

思路

普通棧的push()pop()函式的複雜度為o(1

)\mathcal(1)

o(1)

;而獲取棧最小值min()函式需要遍歷整個棧,複雜度為o(n

)\mathcal(n)

o(n)

。那麼將min()函式複雜度降為o(1

)\mathcal(1)

o(1)

,可通過建立輔助棧實現;

**實現

class

minstack

void

push

(int x)

void

pop()}

inttop()

intmin()

private

: stack<

int> datastk;

stack<

int> minstk;

};

(二) 劍指 offer 59 - ii. 佇列的最大值

思路

對於乙個普通佇列,push_backpop_front的時間複雜度都是 o(1

)\mathcal(1)

o(1)

,因此直接使用佇列的相關操作就可以實現這兩個函式。

對於這種最值問題,可以聯想站隊問題。對於乙個佇列,我們從隊尾往隊首看,若是第i

ii個人的是[1,

i][1, i]

[1,i

]位置的人身高最高的,則這個佇列的最大身高就為第i

ii位置的人身高,佇列前面的人(編號為[1,

i−1]

[1, i-1]

[1,i−1

])無論走幾個,這個佇列的最大身高一直是第i

ii個人的身高。

模擬一下,維護乙個非嚴格遞減的佇列,隊首元素即為佇列的最大值,且是o(1

)\mathcal(1)

o(1)

時間找到的。(可以結合單調棧進行理解,這裡是單調佇列)

可以看到,輔助佇列deque中的隊首元素始終是當前佇列的最大值。

**實現

class

maxqueue

//求佇列的最大值,若maxdeq非空,直接返回隊首元素,否則返回-1

intmax_value()

//向佇列中新增元素

void

push_back

(int value)

//如果說maxdeq非空且佇列的隊尾元素小於當前要加入的元素

//隊尾元素一直出隊,直到隊尾元素的值不小於要加入的元素的值

while

(!maxdeq.

empty()

&& maxdeq.

back()

< value)

maxdeq.

pop_back()

; maxdeq.

push_back

(value)

;//將要加入的元素加入輔助佇列

}//彈出隊首元素

intpop_front()

return-1

;//如果資料隊列為空,則無操作,並返回-1

}private

: deque<

int> datadeq;

//資料佇列

deque<

int> maxdeq;

//輔助佇列

};

類似的題,有劍指 offer 59 - i. 滑動視窗的最大值,這裡維護乙個滑動視窗長度的最值佇列,假設當前佇列中元素的下標範圍為[i−

k,i]

[i-k, i]

[i−k,i

],若是nums[i-1]和當前佇列的隊首元素相同,則最值佇列彈出隊首元素;然後將隊尾元素與num

s[i]

nums[i]

nums[i

]進行比較,若是小於則彈出隊尾元素直至新的隊尾元素不小於num

s[i]

nums[i]

nums[i

]為止;最終再加入num

s[i]

nums[i]

nums[i

],並將當前隊首元素記錄在當前視窗的最大值記錄容器中即可。

(三) 146. lru 快取機制

思路

當時做這道題想成了使用佇列的方法,結果無法解決多次get的問題,整了大半天,只能通過一半的用例,真是欲哭無淚,選用合適的資料結構是相當重要啊!但是實現過程中,已經想到了最近使用過的頁面放到佇列/資料結構一端的思想,與解法是相同的。

該題應當組合使用雙向鍊錶和雜湊表

注意:在雙向鍊錶的實現中,使用乙個偽頭部(dummy head)和偽尾部(dummy tail)標記界限,這樣在新增節點和刪除節點的時候就不需要檢查相鄰的節點是否存在。在單鏈表中,常使用偽頭部節點,排除空鍊錶的情景,簡化程式設計情況。

**實現

//自定義雙向鍊錶,包含其前節點和後節點,鍵值對和結構體建構函式

struct dlinkednode

//帶引數的初始化方式

dlinkednode

(int key,

int value)

:key

(key)

,value

(value)

,prev

(nullptr),

next

(nullptr)}

;class

lrucache

//get函式,獲取由頁面的key值獲取頁面的value值

intget

(int key)

else

return-1

;//若是沒有key值對應的頁面,則返回-1

}void

put(

int key,

int value)

else}}

private

: unordered_map<

int, dlinkednode*

> cache;

dlinkednode* head;

dlinkednode* tail;

int size;

int capacity;

void

addtohead

(dlinkednode* node)

void

removenode

(dlinkednode* node)

void

movetohead

(dlinkednode* node)

dlinkednode*

removetail()

};

O 1 時間複雜度刪除鍊錶元素

package lineartable 鍊錶節點類 class node 鍊錶類 public class linktable 增加節點 public void addnode node node end.next node 刪除節點 時間複雜度為o 1 無需遍歷鍊錶元素 public void d...

刪除鍊錶結點要求O 1 時間複雜度

一,題目 給定鍊錶的頭指標和乙個結點指標,在 o 1 時間刪除該結點。鍊錶結點的定義如下 struct listnode 函式的宣告如下 void deletenode listnode plisthead,listnode ptobedeleted 二,分析 這是一道廣為流傳的 google 面試...

在O 1 時間複雜度刪除鍊錶節點

給定乙個單鏈表中的乙個等待被刪除的節點 非表頭或表尾 請在在o 1 時間複雜度刪除該鍊錶節點。給定1 2 3 4,和節點3,刪除 3之後,鍊錶應該變為1 2 4。因為給定節點在鍊錶的中間,所以不可能用一步步迭代找到這個節點的前驅,那就得換個思路來思考這個問題。題目並未說不可以更改節點的元素,所以可以...