leetcode 146. LRU Cache (medium)

https://leetcode.com/problems/lru-cache/
題目描述
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

模擬LRU存儲過程, 以下是來自維基百科的解釋. 總結起來就是當cache滿了以後, 把最久未操作的地址內容清空出去, 以放置最新的數據.
Least recently used (LRU)
Discards the least recently used items first. This algorithm requires keeping track of what was used when, which is expensive if one wants to make sure the algorithm always discards the least recently used item. General implementations of this technique require keeping “age bits” for cache-lines and track the “Least Recently Used” cache-line based on age-bits. In such an implementation, every time a cache-line is used, the age of all other cache-lines changes. LRU is actually a family of caching algorithms with members including 2Q by Theodore Johnson and Dennis Shasha, and LRU/K by Pat O’Neil, Betty O’Neil and Gerhard Weikum.

The access sequence for the below example is A B C D E D F.
在這裏插入圖片描述
LRU working
In the above example once A B C D gets installed in the blocks with sequence numbers (Increment 1 for each new Access) and when E is accessed, it is a miss and it needs to be installed in one of the blocks. According to the LRU Algorithm, since A has the lowest Rank(A(0)), E will replace A.

解題思路

先考慮不使用有序字典, 建立三個列表, cache存放數據, cacheKey存放索引值, evictQ存放地址時序序列, 隊首是最久未操作過的地址, 隊尾是最新操作過的地址.

本題的核心就是維護一個隊列evictQ, 該隊列保存的是各個地址的操作時序情況. 每次操作過某一地址的數據 (無論get還是put), 就將當前地址值放入evictQ的隊尾. cache滿的時候, 彈出隊首地址的內容, 放入數據.

get和put操作的時間複雜度都是O(1), 空間複雜的是O(n)

代碼

class LRUCache:

    def __init__(self, capacity: int):
        self.cache = [] # 存放數據
        self.cacheKey = [] # 存放索引值
        self.evictQ = [_ for _ in range(capacity)] # the order of evicting  #操作時序隊列, 隊首是最久未操作過的地址, 隊尾是最新操作過的地址
        self.capacity = capacity
        self.used = 0
        
    def get(self, key: int) -> int:
        if key in self.cacheKey:
            index = self.cacheKey.index(key)
            self.evictQ.remove(index)
            self.evictQ.append(index)
            return self.cache[index]
        else:
            return -1
    def put(self, key: int, value: int) -> None:
        # if the key is already in the cache
        if key in self.cacheKey:
            index = self.cacheKey.index(key)
            self.evictQ.remove(index)
            self.evictQ.append(index)
            self.cache[index] = value
        # if the key is not exist
        # 1. if the cache is not full
        # 2. if the cache is full, evict the first of the cache
        else:
            if self.used != self.capacity:
                index = self.evictQ.pop(0)
                self.cacheKey.insert(index, key)
                self.cache.insert(index, value)
                self.evictQ.append(index) # index move to the tail
                self.used += 1
            # 
            elif self.used == self.capacity:
                index = self.evictQ.pop(0) # pop the head in the queue
                self.cacheKey[index] = key
                self.cache[index] = value
                self.evictQ.append(index)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章