在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

設(shè)計并實現(xiàn)一個滿足LRU約束的數(shù)據(jù)結(jié)構(gòu)

冬至子 ? 來源:i余數(shù) ? 作者:i余數(shù) ? 2023-06-07 17:05 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

題目

請你設(shè)計并實現(xiàn)一個滿足 「LRU (最近最少使用) 緩存」 約束的數(shù)據(jù)結(jié)構(gòu)。

實現(xiàn) LRUCache 類:

  • LRUCache(int capacity)「正整數(shù)」 作為容量 capacity 初始化 LRU 緩存
  • int get(int key) 如果關(guān)鍵字 key 存在于緩存中,則返回關(guān)鍵字的值,否則返回 -1
  • void put(int key, int value) 如果關(guān)鍵字 key 已經(jīng)存在,則變更其數(shù)據(jù)值 value ;如果不存在,

則向緩存中插入該組 key-value 。如果插入操作導(dǎo)致關(guān)鍵字數(shù)量超過 capacity ,則應(yīng)該 「逐出」 最久未使用的關(guān)鍵字。

1.jpg

示例:

輸入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
輸出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解釋
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 緩存是 {1=1}
lRUCache.put(2, 2); // 緩存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 該操作會使得關(guān)鍵字 2 作廢,緩存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 該操作會使得關(guān)鍵字 1 作廢,緩存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

提示:

1.jpg

題解(哈希表 + 雙向鏈表)

解題之前先了解一下什么是 「LRU緩存」 , LRU 的英文全稱為 Latest Recently Used,即 「最近最少使用」 。在緩存占滿的時候,先刪除最舊的數(shù)據(jù)。

1.jpg

Java 代碼實現(xiàn)

class LRUCache {

    private int capacity;

    private Map< Integer, ListNode > cache;

    // 保護節(jié)點,protectHead.next 為head節(jié)點, protectTail.pre為tail節(jié)點
    private ListNode protectHead = new ListNode();
    private ListNode protectTail = new ListNode();

    public LRUCache(int capacity) {
        this.capacity = capacity;
        cache = new HashMap<  >(capacity);
        protectHead.next = protectTail;
        protectTail.pre = protectHead;
    }


    // 刪除指定節(jié)點
    private void remove(ListNode listNode){
        listNode.pre.next = listNode.next;
        listNode.next.pre = listNode.pre;

        listNode.pre = null;
        listNode.next = null;
    }

    // 添加到末尾
    private void addToTail(ListNode listNode){

        protectTail.pre.next = listNode;
        listNode.pre = protectTail.pre;

        listNode.next = protectTail;
        protectTail.pre = listNode;
        
    }

    // 從當(dāng)前位置移動到末尾
    private void moveToTail(ListNode listNode){
        
        this.remove(listNode);
        this.addToTail(listNode);
        
    }
    
    public int get(int key) {
        if(cache.containsKey(key)){
            ListNode listNode = cache.get(key);
            this.moveToTail(listNode);
            return listNode.value;
        }else{
            return -1;
        }

    }
    
    public void put(int key, int value) {
        if(cache.containsKey(key)){
            // 將 key 移動到最新的位置
            // 1. 在舊的位置刪除
            // 2. 追加key到鏈表末尾
            ListNode listNode = cache.get(key);

            // 這里必須重新賦值,雖然緩沖已經(jīng)存在了,但是可能值不一樣。
            listNode.value = value;
            this.moveToTail(listNode);
            return;

        }

        if(cache.size() == capacity){
            // 1. 找到最舊的數(shù)據(jù),也就是鏈表的head,刪除head
            // 2. 在cache map 中刪除 head對應(yīng)的key
            ListNode headNode = protectHead.next;
            this.remove(headNode);
            cache.remove(headNode.key);
        }


        // 1. 添加新的key到cache map
        // 2. 追加新的key到鏈表末尾

        ListNode listNode = new ListNode();
        listNode.key = key;
        listNode.value = value;

        this.addToTail(listNode);
        cache.put(key, listNode);

    }
}

class ListNode{
    int key;
    int value;
    ListNode pre;
    ListNode next;

}

Go 代碼實現(xiàn)

// 定義雙向鏈表
type MyListNode struct {
    key, value int
    pre, next *MyListNode
}

type LRUCache struct { 
    size, capacity int
    cache map[int]*MyListNode
    protectHead, protectTail *MyListNode
}


func Constructor(capacity int) LRUCache {
    lruCache := LRUCache{
        size: 0,
        capacity: capacity,
        cache: map[int]*MyListNode{},
        protectHead: &MyListNode{},
        protectTail: &MyListNode{},
    }

    lruCache.protectHead.next = lruCache.protectTail
    lruCache.protectTail.pre = lruCache.protectHead
    return lruCache
}


func (this *LRUCache) Get(key int) int {
    if listNode, ok := this.cache[key]; ok {
        this.moveToTail(listNode);
        return listNode.value;
    }else{
        return -1
    }
}


func (this *LRUCache) Put(key int, value int)  {
    if listNode, ok := this.cache[key]; ok {
        listNode.value = value;
        this.moveToTail(listNode);
        return;
    }
    if(this.size == this.capacity){
        headNode := this.protectHead.next;
        this.remove(headNode);
        delete(this.cache, headNode.key);
        this.size--
    }

    listNode := &MyListNode{
        key: key,
        value: value,
    }


    this.addToTail(listNode)
    this.cache[key] = listNode
    this.size++
}

// 刪除指定節(jié)點
func (this *LRUCache) remove(listNode *MyListNode){
    listNode.pre.next = listNode.next;
    listNode.next.pre = listNode.pre;

    listNode.pre = nil;
    listNode.next = nil;
}


// 添加到末尾
func (this *LRUCache) addToTail(listNode *MyListNode){
    this.protectTail.pre.next = listNode
    listNode.pre = this.protectTail.pre

    listNode.next = this.protectTail
    this.protectTail.pre = listNode
}


// 從當(dāng)前位置移動到末尾
func (this *LRUCache) moveToTail(listNode *MyListNode){
    this.remove(listNode);
    this.addToTail(listNode);
}

復(fù)雜度分析

1.jpg

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2987

    瀏覽量

    107683
  • cache技術(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    41

    瀏覽量

    1210
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    什么是數(shù)據(jù)結(jié)構(gòu)(Data Structrue)

    一個一個元素數(shù)據(jù)對象:具有相同特性的數(shù)據(jù)元素的集合結(jié)構(gòu)數(shù)據(jù)元素之間具有的關(guān)系(聯(lián)系) 二. 
    發(fā)表于 02-09 17:17

    GPIB命令的數(shù)據(jù)結(jié)構(gòu)

    GPIB命令結(jié)點;考慮程序實現(xiàn)的效率問題以及管理維護方面的因素,對普通的樹進行改造,從而形成特有的"GPIB命令樹"。【關(guān)鍵詞】:通用接口總線(GPIB);;數(shù)據(jù)結(jié)構(gòu);;樹
    發(fā)表于 04-24 09:44

    【原創(chuàng)】Android開發(fā)—Lru核心數(shù)據(jù)結(jié)構(gòu)實現(xiàn)突破緩存框架

    【原創(chuàng)】Android開發(fā)—Lru核心數(shù)據(jù)結(jié)構(gòu)實現(xiàn)突破緩存框架回復(fù)即可獲取下載鏈接[hide=d15]鏈接:http://pan.baidu.com/s/1c2BfjsW 密碼:bta5 更多學(xué)習(xí)資料加Q:1352716312,
    發(fā)表于 06-21 16:58

    數(shù)據(jù)結(jié)構(gòu)

    數(shù)據(jù)的邏輯結(jié)構(gòu)分為線性結(jié)構(gòu)和非線性結(jié)構(gòu)。非空的線性結(jié)構(gòu)
    發(fā)表于 03-04 14:13

    常見的數(shù)據(jù)結(jié)構(gòu)

    順序表結(jié)構(gòu)的底層實現(xiàn)借助的就是數(shù)組,因此對于初學(xué)者來說,可以把順序表完全等價為數(shù)組,但實則不是這樣。數(shù)據(jù)結(jié)構(gòu)是研究數(shù)據(jù)存儲方式的門學(xué)科,它
    發(fā)表于 05-10 07:58

    GPIB命令的數(shù)據(jù)結(jié)構(gòu)

    針對GPIB命令的結(jié)構(gòu),提出種存儲GPIB命令的數(shù)據(jù)結(jié)構(gòu)。根據(jù)GPIB命令的層次關(guān)系的特點,選擇數(shù)據(jù)結(jié)構(gòu)中“樹”的概念來存儲GPIB命令結(jié)點;
    發(fā)表于 02-10 16:20 ?70次下載

    GPIB命令的數(shù)據(jù)結(jié)構(gòu)

    針對GPIB命令的結(jié)構(gòu),提出種存儲GPIB命令的數(shù)據(jù)結(jié)構(gòu)。根據(jù)GPIB命令的層次關(guān)系的特點,選擇數(shù)據(jù)結(jié)構(gòu)中“樹”的概念來存儲GPIB命令結(jié)點;
    發(fā)表于 01-04 10:13 ?0次下載

    數(shù)據(jù)結(jié)構(gòu)是什么_數(shù)據(jù)結(jié)構(gòu)有什么用

    數(shù)據(jù)結(jié)構(gòu)是計算機存儲、組織數(shù)據(jù)的方式。數(shù)據(jù)結(jié)構(gòu)是指相互之間存在種或多種特定關(guān)系的數(shù)據(jù)元素的集合。通常情況下,精心選擇的
    發(fā)表于 11-17 14:45 ?1.6w次閱讀
    <b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>是什么_<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>有什么用

    什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)?數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實例分析

    本文檔的主要內(nèi)容詳細介紹的是什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)?數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實例分析包括了:數(shù)據(jù)結(jié)構(gòu)在串口通信當(dāng)中的應(yīng)用,數(shù)據(jù)結(jié)構(gòu)在按鍵
    發(fā)表于 09-26 15:45 ?14次下載
    什么是<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?為什么要學(xué)習(xí)<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>的應(yīng)用實例分析

    如何解決數(shù)據(jù)結(jié)構(gòu)設(shè)計最大頻率棧問題?

    。 力扣第 895 題要求我們實現(xiàn)特殊的數(shù)據(jù)結(jié)構(gòu)「最大頻率棧」,比較有意思,讓我們實現(xiàn)下面這兩
    的頭像 發(fā)表于 03-02 11:02 ?1600次閱讀

    數(shù)據(jù)結(jié)構(gòu)解決滑動窗口問題

    前文用 [單調(diào)棧解決三道算法問題]介紹了單調(diào)棧這種特殊數(shù)據(jù)結(jié)構(gòu),本文寫類似的數(shù)據(jù)結(jié)構(gòu)「單調(diào)隊列」。 也許這種數(shù)據(jù)結(jié)構(gòu)的名字你沒聽過,其
    的頭像 發(fā)表于 04-19 10:50 ?908次閱讀
    <b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>解決滑動窗口問題

    如何理解掌握Java數(shù)據(jù)結(jié)構(gòu)?

    Java 數(shù)據(jù)結(jié)構(gòu)是 Java 程序員必須掌握的重要知識之。
    的頭像 發(fā)表于 06-06 15:53 ?1062次閱讀

    NetApp的數(shù)據(jù)結(jié)構(gòu)是如何演變的

    統(tǒng)一數(shù)據(jù)跨分布式資源進行管理,以實現(xiàn)數(shù)據(jù)移動的致性和控制,安全、可見性、保護和訪問。 本文定義了數(shù)據(jù)結(jié)構(gòu)及其體系
    發(fā)表于 08-25 17:15 ?0次下載
    NetApp的<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>是如何演變的

    epoll的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

    先看下 eventpoll 這個數(shù)據(jù)結(jié)構(gòu),這個數(shù)據(jù)結(jié)構(gòu)是我們在調(diào)用 epoll_create 之后內(nèi)核創(chuàng)建的句柄,表示了
    的頭像 發(fā)表于 11-10 10:20 ?1098次閱讀
    epoll的基礎(chǔ)<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>

    redis數(shù)據(jù)結(jié)構(gòu)的底層實現(xiàn)

    Redis是種內(nèi)存鍵值數(shù)據(jù)庫,常用于緩存、消息隊列、實時數(shù)據(jù)分析等場景。它的高性能得益于其精心設(shè)計的數(shù)據(jù)結(jié)構(gòu)和底層實現(xiàn)。本文將詳細介紹Re
    的頭像 發(fā)表于 12-05 10:14 ?837次閱讀
    主站蜘蛛池模板: 日本视频三区 | 亚洲欧美人成网站综合在线 | 一二三四日本视频社区 | 欧美一卡二卡3卡4卡无卡六卡七卡科普 | 欧美肥胖女人bbwbbw视频 | 天天综合天天干 | 亚洲乱码卡一卡二卡三永久 | 中文字幕在线天堂 | 美女天天操 | 黄色在线视频免费看 | 欧美成人午夜精品一区二区 | 在线观看色视频 | 日韩一级在线视频 | 国产亚洲精品久久久久久午夜 | 日本不卡视频在线播放 | 真人午夜a一级毛片 | 男人女人的免费视频网站 | 久久艹人人艹 | 手机看片自拍自自拍日韩免费 | 亚洲三级电影 | 欧美人与zoxxxx另类9 | 一本到中文字幕高清不卡在线 | 欧美伊久线香蕉线新在线 | 激情文学综合丁香 | 理论片久久 | 国产小视频在线播放 | 天天综合射 | 黄网站在线观看永久免费 | 高清视频免费 | 视频在线一区二区 | 美女国产 | 一区二区三区福利 | 欧美夜夜 | 亚洲欧美视频一区二区 | 亚洲无吗在线视频 | 国产性做久久久久久 | 色狠狠综合网 | 在线免费观看黄色小视频 | 免费视频爰爱太爽了 | 香港三级在线视频 | 国模一区二区三区私啪啪 |