每日一題 Leetcode 146

2021-10-06 11:45:32 字數 3224 閱讀 1017

運用你所掌握的資料結構,設計和實現乙個 lru (最近最少使用) 快取機制。它應該支援以下操作: 獲取資料 get 和 寫入資料 put 。

獲取資料 get(key) - 如果金鑰 (key) 存在於快取中,則獲取金鑰的值(總是正數),否則返回 -1。

寫入資料 put(key, value) - 如果金鑰已經存在,則變更其資料值;如果金鑰不存在,則插入該組「金鑰/資料值」。當快取容量達到上限時,它應該在寫入新資料之前刪除最久未使用的資料值,從而為新的資料值留出空間。

高階:

你是否可以在 o(1) 時間複雜度內完成這兩種操作?

lrucache cache = new lrucache( 2 /* 快取容量 */ );

cache.put(1, 1);

cache.put(2, 2);

cache.get(1); // 返回 1

cache.put(3, 3); // 該操作會使得金鑰 2 作廢

cache.get(2); // 返回 -1 (未找到)

cache.put(4, 4); // 該操作會使得金鑰 1 作廢

cache.get(1); // 返回 -1 (未找到)

cache.get(3); // 返回 3

cache.get(4); // 返回 4

參考精選題解,鍵值對的操作必然是要用到雜湊表的,關於如何記錄資料的最近訪問狀態,有兩個想法:

用佇列,剛被push的鍵值一定是在隊尾。但是剛剛訪問的乙個鍵很可能是在隊中的,常數時間內無法把它提到隊尾去;

用老化機制,為所有的鍵值對再設定乙個變數記錄它們在cache中已經存在的回合數。每進行push或者get,其他鍵對映的該變數就要加一;當cache不足時挑選老化指數最大的鍵值對pop掉。這樣的話,仍然會涉及到遍歷問題,o(1)內無法完成。

目前能滿足常數複雜度的只有雜湊表查詢,其餘的會使得複雜度不滿足條件。python中倒是有乙個非常雞賊的做法,用collections.ordereddict。但是如果你真的在面試時這麼寫了,等著被面試官問ordereddict的底層實現方式吧——兜兜轉轉還是會回到本題的考點:雙向鍊錶+雜湊表。

這裡的雙向鍊錶代替了設想1裡面的佇列,它在移動中間節點的時候只需要常數複雜度就能完成。

確認了需要用到的資料結構之後,實現的時候需要注意細節。雜湊表是存鍵+鍊錶節點,節點裡包含鍵+值+前後指標。上**:

class

listnode

:def

__init__

(self, key =

none

, value =

none):

self.key = key

self.value = value

self.prev =

none

self.

next

=none

class

lrucache

:def

__init__

(self, capacity:

int)

: self.capacity = capacity

self.hashmap =

self.head = listnode(

) self.tail = listnode(

) self.head.

next

= self.tail

self.tail.prev = self.head

definsert_tail

(self, key:

int)

: node = self.hashmap[key]

node.prev.

next

= node.

next

node.

next

.prev = node.prev

node.prev = self.tail.prev

node.

next

= self.tail

self.tail.prev.

next

= node

self.tail.prev = node

defget(self, key:

int)

->

int:

if key in self.hashmap:

self.insert_tail(key)

res = self.hashmap.get(key,-1

)return res if res ==-1

else res.value

defput(self, key:

int, value:

int)

->

none

:if key in self.hashmap:

self.hashmap[key]

.value = value

self.insert_tail(key)

else:if

len(self.hashmap)

== self.capacity:

self.hashmap.pop(self.head.

next

.key)

self.head.

next

= self.head.

next

.next

self.head.

next

.prev = self.head

new = listnode(key, value)

self.hashmap[key]

= new

new.prev = self.tail.prev

new.

next

= self.tail

new.prev.

next

= new

self.tail.prev = new

# your lrucache object will be instantiated and called as such:

# obj = lrucache(capacity)

# param_1 = obj.get(key)

# obj.put(key,value)

乙個小注釋,hashmap.get(key, -1)表示如果hashmap中有key,返回對映值,否則返回-1.

每日一題 LeetCode

在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。示例 1 輸入 7,5,6,4 輸出 5 限制 0 陣列長度 50000 思想是 分治演算法 所有的 逆序對 於 3 個部分 左邊區間的逆序對 右邊區間的逆序對 橫跨兩個區間的...

LRU快取機制 leetcode146

運用你所掌握的資料結構,設計和實現乙個 lru 最近最少使用 快取機制。它應該支援以下操作 獲取資料 get 和 寫入資料 put 獲取資料 get key 如果金鑰 key 存在於快取中,則獲取金鑰的值 總是正數 否則返回 1。寫入資料 put key,value 如果金鑰已經存在,則變更其資料值...

leetcode 146 實現LRU演算法

lru 最近最少使用。不管是讀還是寫,都是對此資料重新整理他的時間 時間由雙向鍊錶的順序決定 class lrucache public node int key,int value private node dummyhead new node private node dummytail new...