LeetCode 460. LFU Cache

10-10 LeetCode 460. LFU Cache

LFU Cache

Description

Design and implement a data structure for Least Frequently Used (LFU) 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 reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.

Follow up:
Could you do both operations in O(1) time complexity?

為最不頻繁使用緩存技術(shù)設(shè)計(jì)一種數(shù)據(jù)結(jié)構(gòu),它需要支持getput方法。

get(key) - 返回key對(duì)應(yīng)的值如果key存在于緩存中,否則返回-1.

put(key, value) - 插入key, value鍵值對(duì),當(dāng)緩存區(qū)滿了以后,需要?jiǎng)h除最不頻繁使用的key, value對(duì)。為了滿足這個(gè)目的,當(dāng)多個(gè)key有相同的頻率時(shí),上一次使用時(shí)間距離當(dāng)前時(shí)間最長的key將被刪除。

要求
所有操作在O(1)時(shí)間復(fù)雜度內(nèi)完成

知識(shí)補(bǔ)充

Least Frequently Used cache,如果我沒記錯(cuò)的話,這是在學(xué)計(jì)算機(jī)組成原理時(shí)學(xué)到的一個(gè)知識(shí)。cpu對(duì)緩存區(qū)域的數(shù)據(jù)讀取速度比對(duì)外存中的數(shù)據(jù)讀取要快很多,所以為了提高cpu的運(yùn)行速度,將一些常用的數(shù)據(jù)預(yù)先存入緩存,就可以減少數(shù)據(jù)讀取的時(shí)間消耗,從而提高cpu運(yùn)行效率。但是我們不可能提前知道cpu需要什么數(shù)據(jù),緩存的大小也有限,不可能存下所有數(shù)據(jù),所以設(shè)計(jì)一個(gè)算法來控制存入緩存中的數(shù)據(jù)是有必要的。想象一下,cpu每次取數(shù)據(jù),緩存中都沒有,都需要從外存中獲取,那么這個(gè)緩存設(shè)計(jì)的就沒有一點(diǎn)意義。所以需要提高cpu命中緩存中數(shù)據(jù)的幾率。因此有很多相關(guān)的算法,可以上網(wǎng)搜索一下。

Solution 1:

這道題的難點(diǎn)就在于要求所有操作的時(shí)間復(fù)雜度都為O(1),于是我們很自然而然的就想到用哈希表這種數(shù)據(jù)結(jié)構(gòu),在python中字典就是這樣的一種結(jié)構(gòu)。不管數(shù)據(jù)量有多大,在字典中查詢key值的時(shí)間復(fù)雜度都為O(1)。

但是光一個(gè)字典肯定是不夠的,因?yàn)槲覀冃枰獎(jiǎng)h除最不頻繁使用的key。因此還需要一個(gè)字典來存儲(chǔ)每一個(gè)頻率下對(duì)應(yīng)的key有哪些,例如頻率1次的有key1,key2,頻率3次的有key3...,

想到這我就開始寫代碼了,寫完提交后才發(fā)現(xiàn),這樣的時(shí)間復(fù)雜度還是不能達(dá)到O(1)。因?yàn)橥ㄟ^key不能在O(1)時(shí)間內(nèi)找到key對(duì)應(yīng)的頻率,所以還需要額外的一個(gè)字典來存儲(chǔ)key以及key對(duì)應(yīng)的頻率。現(xiàn)在應(yīng)該是很清晰了,我直接貼上代碼,代碼的大多數(shù)位置也有注釋。

代碼:

class LFUCache(object):

def __init__(self, capacity):
    """
    :type capacity: int
    """
    self.capacity = capacity
    self.cache = {} # 存放存入的鍵值對(duì)
    self.frequency = {} # 存放每個(gè)頻率中出現(xiàn)的key,如{1:[key1,key2], 2:[key3]}
    self.cache_index = {} # 存放key對(duì)應(yīng)的頻率, 如{key1:1, key2:1, key3:2}

def get(self, key):
    """
    :type key: int
    :rtype: int
    """
    if key not in self.cache:
        return -1
    index = self.cache_index[key]
    self.frequency[index].remove(key)
    if self.frequency[index] == []:
        del self.frequency[index]
    if index+1 in self.frequency:
        self.frequency[index+1].append(key)
    else:
        self.frequency[index+1] = [key]
    self.cache_index[key] += 1
    return self.cache[key]
    

    

def put(self, key, value):
    """
    :type key: int
    :type value: int
    :rtype: void
    """
    if self.capacity <= 0:
        return 
    if key in self.cache:
        # 如果put一個(gè)已經(jīng)存在的key,修改它的value和frequency
        self.cache[key] = value
        self.get(key)
        return
    if len(self.cache) == self.capacity:
        for times in self.frequency: # 因?yàn)樽值溆行颍缘谝粋€(gè)肯定是頻率最小的,刪除后通過break退出循環(huán)
            key_of_cache = self.frequency[times][0] # 取出頻率最小的key,并刪除
            del self.cache[key_of_cache]
            del self.cache_index[key_of_cache]
            self.frequency[times] = self.frequency[times][1:]
            if self.frequency[times] == []:
                del self.frequency[times]
                break
    # 插入一個(gè)新值,頻率初始值為1
    self.cache[key] = value
    if 1 in self.frequency:
        self.frequency[1].append(key)
    else:
        self.frequency[1] = [key]
    self.cache_index[key] = 1

感想

每天做這個(gè)還是耗費(fèi)挺多時(shí)間的,因?yàn)樗讲桓撸鲆活}就需要很長時(shí)間,然后還需要記錄下來,我可能要減少發(fā)布的頻率了...............

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。