# **Leetcode筆記(LRU Cache)** :::info :information_source: 題目 : LRU Cache, 類型 : linked list , 等級 : medium 日期 : 2023/05/30,2023/07/03,2023/11/19,2024/10/05 ::: ### 嘗試 加油加油,微軟題目!! 要建立一個double linked list,因為這樣才可以確保同時找的到前面和後面的node -> A double-linked list allows for efficient removal and insertion operations in constant time (O(1)) linked list的部分 -> 用right和left去控制最左跟最右,其他剩下的node夾在中間 -> get(取數字) 優先順序會提升 所以要先remove再insert -> put(加數字) 同時加在hashmap跟鍊表,如果超出capacity則刪除左邊的 hashmap的部分 -> hashmap[key] = Node(key, value) -> 用來記錄這個node到底有沒有存在 2023/07/03 ```python # double linked list class Node: def __init__(self, key = 0, val = 0): self.key, self.val = key, val self.next, self.pre = None, None # ->是next <-是pre class LRUCache: def __init__(self, capacity: int): self.hashmap = {} # hashmap[key] = Node(key, value) self.capacity = capacity self.left, self.right = Node(), Node() self.left.next, self.right.pre = self.right, self.left def remove(self, node): # 用自己的left right去操作 l, r = node.pre, node.next l.next, r.pre = r, l def insert(self, node): # 總是加到最右邊 l = self.right.pre l.next, self.right.pre = node, node node.pre, node.next = l, self.right def get(self, key: int) -> int: # 鍊表 : 如果key存在 那就先刪除它再加入它(改優先順序) # 字典 : 如果存在不用動 只是要取值而已 if key in self.hashmap: self.remove(self.hashmap[key]) self.insert(self.hashmap[key]) return self.hashmap[key].val return -1 def put(self, key: int, value: int) -> None: # 加東西 # 鍊表 : 一律刪除再更新(數值可能變) # 字典 : 不用管 更新就對了 if key in self.hashmap: self.remove(self.hashmap[key]) self.hashmap[key] = Node(key, value) # 字典 self.insert(self.hashmap[key]) # 鍊表 # 超過了 刪掉最左的 if len(self.hashmap) > self.capacity: lru = self.left.next del self.hashmap[lru.key] self.remove(lru) ``` 2023/11/19 ```python class ListNode: def __init__(self, val, key, post=None, pre=None): self.val = val self.key = key self.post = post self.pre = pre class LinkedList: def __init__(self, R, L): self.L = L self.R = R self.L.post = self.R self.R.pre = self.L self.size = 0 def delete(self, node): left, right = node.pre, node.post if left is not None: left.post = right if right is not None: right.pre = left del node self.size -= 1 def add(self, node): # always add on the right hand side left = self.R.pre left.post, self.R.pre = node, node node.post, node.pre = self.R, left self.size += 1 class LRUCache: def __init__(self, capacity: int): self.capacity = capacity self.record = dict() # dict[key] = Node(key, val) self.R, self.L = ListNode(0, 0), ListNode(0, 0) self.linked = LinkedList(self.R, self.L) def get(self, key: int) -> int: if key in self.record: self.linked.delete(self.record[key]) self.linked.add(self.record[key]) return self.record[key].val return -1 def put(self, key: int, value: int) -> None: if key in self.record: self.linked.delete(self.record[key]) # remove the old one self.record[key] = ListNode(value, key) self.linked.add(self.record[key]) if self.linked.size > self.capacity: left = self.L.post self.linked.delete(left) del self.record[left.key] ``` 2023/11/24 記得double linked list是要指向node ```python class Node: def __init__(self, key = 0, val = 0, prev = None, post = None): self.key = key self.val = val self.prev = prev self.post = post class LinkedList: def __init__(self): self.R, self.L = Node(), Node() self.L.post = self.R self.R.prev = self.L def add(self, node): # l <-> R # l <-> node <-> R l = self.R.prev l.post, self.R.prev = node, node node.prev, node.post = l, self.R def delete(self, node): # l <-> node <-> r # l <-> r l, r = node.prev, node.post if l and r: l.post, r.prev = r, l del node class LRUCache: def __init__(self, capacity: int): self.capacity = capacity self.hashmap = dict() # key : double linked list self.dLinkedList = LinkedList() # def get(self, key: int) -> int: if key in self.hashmap: self.dLinkedList.delete(self.hashmap[key]) self.dLinkedList.add(self.hashmap[key]) return self.hashmap[key].val return -1 def put(self, key: int, value: int) -> None: if key in self.hashmap: self.dLinkedList.delete(self.hashmap[key]) self.hashmap[key] = Node(key, value) self.dLinkedList.add(self.hashmap[key]) if len(self.hashmap) > self.capacity: node = self.dLinkedList.L.post self.dLinkedList.delete(node) del self.hashmap[node.key] ``` 2023/12/09 ```python """ L->2->3<->1<->R class Node(): key, val : indicator pre, post : pointer class DLL(): R, L : boundary add : on right delete : on left class LRUCache(): hashmap : dict (key (key) : value (Node)) DLL : store hashamp[key] """ class Node(): def __init__(self, key = 0, val = 0): self.key = key self.val = val self.pre = None self.post = None class DLL(): def __init__(self): self.R = Node() self.L = Node() self.R.pre = self.L self.L.post = self.R def add(self, node): # temp <-> R # temp <-> node <-> R temp = self.R.pre temp.post = node self.R.pre = node node.pre, node.post = temp, self.R def delete(self, node): # temp_l <-> node <-> temp_r # temp_l <-> temp_r temp_l, temp_r = node.pre, node.post temp_l.post = temp_r temp_r.pre = temp_l class LRUCache(object): def __init__(self, capacity): self.cap = capacity self.dll = DLL() # store hashamp[key] self.hashmap = dict() # key (key) : value (Node) def get(self, key): if key in self.hashmap: self.dll.delete(self.hashmap[key]) self.dll.add(self.hashmap[key]) return self.hashmap[key].val return -1 def put(self, key, value): if key in self.hashmap: self.dll.delete(self.hashmap[key]) self.hashmap[key] = Node(key, value) self.dll.add(self.hashmap[key]) if len(self.hashmap) > self.cap: temp = self.dll.L.post self.dll.delete(self.hashmap[temp.key]) del self.hashmap[temp.key] ``` 2024/10/05 加油,記得當初在面試微軟前,寫到這題,覺得如果面試官問我這題,那真的完蛋。雖然最後面試結果還是沒上,但至少為後來奠定基礎 謝謝當時的自己,現在整個架構熟悉多了 ```python class Node: def __init__(self, key = -1, val = -1, pre = None, post = None): self.key = key self.val = val self.pre = pre self.post = post class DoubleLinkedlist: def __init__(self): self.R = Node() self.L = Node() self.R.pre = self.L self.L.post = self.R def remove(self, node): # node on the linkedlist # l <-> node <-> r # l <-> r l, r = node.pre, node.post l.post = r r.pre = l return def add(self, node): # add on the right # l <-> R # l <-> node <-> R l = self.R.pre l.post, self.R.pre = node, node node.pre, node.post = l, self.R return class LRUCache: def __init__(self, capacity: int): self.record = {} # key : Node self.dl = DoubleLinkedlist() self.capacity = capacity def get(self, key: int) -> int: if key in self.record: node = self.record[key] self.dl.remove(node) self.dl.add(node) return node.val else: return -1 def put(self, key: int, value: int) -> None: if key in self.record: node = self.record[key] node.val = value self.dl.remove(node) self.dl.add(node) else: # add in cache if len(self.record) == self.capacity: # reach limit garbage = self.dl.L.post self.dl.remove(garbage) del self.record[garbage.key] new_node = Node(key, value) self.dl.add(new_node) self.record[key] = new_node return # Your LRUCache object will be instantiated and called as such: # obj = LRUCache(capacity) # param_1 = obj.get(key) # obj.put(key,value) ``` --- ### **優化** ```python class Node: def __init__(self, key, value): self.key, self.value = key, value # 雙向指標 self.pre, self.nxt = None, None class LRUCache: def __init__(self, capacity: int): self.cap = capacity self.cache = {} # cache[key] = Node(key, value) # 左極點與右極點 # 有寫self代表是全域變數 之後其他函數可以訪問 self.left, self.right = Node(0, 0), Node(0, 0) self.left.nxt, self.right.pre = self.right, self.left def remove(self, node): l, r = node.pre, node.nxt l.nxt, r.pre = r, l def insert(self, node): # 加到右邊 l, r = self.right.pre, self.right r.pre, l.nxt = node, node node.pre, node.nxt = l, r def get(self, key: int) -> int: # 順便把最新的加到linked list右邊 if key in self.cache: self.remove(self.cache[key]) self.insert(self.cache[key]) return self.cache[key].value return -1 def put(self, key: int, value: int) -> None: if key in self.cache: self.remove(self.cache[key]) # 要update self.cache[key] = Node(key, value) self.insert(self.cache[key]) if len(self.cache) > self.cap: lm = self.left.nxt # node self.remove(lm) del self.cache[lm.key] # 徹底刪除 ``` --- **:warning: 錯誤語法** :::warning ::: **:thumbsup:學習** :::success ::: **思路** **講解連結** https://www.youtube.com/watch?v=7ABFKPK2hD4&ab_channel=NeetCode Provided by. Neetcode ###### tags: `linked list` `medium` `leetcode`