[LeetCode] 146. LRU Cache

Posted wengle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[LeetCode] 146. LRU Cache相关的知识,希望对你有一定的参考价值。

1. 原题链接:https://leetcode.com/problems/lru-cache/

2. 解题思路

  1. 为了增删改查都有较高的性能,使用双向链表和哈希表的组合
  2. 针对LRU,哈希表对于查询和修改可以实现O(1)的时间复杂度,但是无法在O(1)时间复杂度实现删除操作
  3. 双向链表可以很好的实现O(1)时间复杂度的增加和删除,因此需要将双向链表和哈希表结合起来一起使用,这两种数据结构的结合点在于哈希表的value存储的是双向链表某个节点的地址(也就是:哈希表的value是一个指向双向链表某个节点的指针)
  4. 越靠近双向链表头部的节点,表示你最近刚访问过,越靠近双向链表尾部的节点,表示最近很少访问,最后一个节点表示最近访问最少

3. 算法

  1. 对于get操作,如果节点存在将其从当前位置摘除,并将该节点插入到链表头部;否则,返回-1
  2. 对于put操作,如果key存在,更新value;否则,检查当前capacity是否已满,如果已满,删除最后一个节点(也就是:最近最少访问的节点)和哈希表对应的key;然后,创建包含key、value的新节点,将其插入链表头部

4. 实现

struct Node {
    int key; //为了删除节点时,同时删除hash表中的key
    int val;
    Node *next;
    Node *prev;
    Node(int k, int v){
        key = k;
        val = v;
        next = NULL;
        prev = NULL;
    }
};

class LRUCache {
public:
    LRUCache(int capacity) {
        size = capacity;
        //哑节点可以化解很多异常情况
        Node *dummy1 = new Node(-1, -1);
        Node *dummy2 = new Node(-1, -1);
        head = dummy1;
        tail = dummy2;
        head->next = dummy2;
        tail->prev = dummy1;
    }

    int get(int key) {
        map<int, Node*>::iterator iter;
        iter = table.find(key);
        if(iter != table.end()){
            Node *cur = iter->second;
            //从当前位置摘掉
            cur->prev->next = cur->next;
            cur->next->prev = cur->prev;
            //将该节点插入头部
            cur->next = head->next;
            cur->prev = head;
            head->next->prev = cur;
            head->next = cur;
            return cur->val;
        }
        return -1;
    }

    void put(int key, int value) {
        if(get(key) > 0){
            //更新已存在key的value
            // head->next->val = value;
            table[key]->val = value;
            return;
        }

        //当容量为0时,先删除,再插入
        if(size == 0){
            Node *del_node = tail->prev;
            del_node->next->prev = del_node->prev;
            del_node->prev->next = del_node->next;
            del_node->prev = NULL;
            del_node->next = NULL;
            //先删除hash表中的key,再删除节点
            table.erase(del_node->key);
            delete del_node;
            size++;
        }
        Node *node = new Node(key, value);
        //将其插入头部
        node->next = head->next;
        node->prev = head;
        head->next->prev = node;
        head->next = node;
        table[key] = node;
        size--;
    }

private:
    map<int, Node*> table;
    int size;
    Node *head;
    Node *tail;
};

以上是关于[LeetCode] 146. LRU Cache的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 146 LRU Cache

leetcode146- LRU Cache- hard

[LeetCode] 146. LRU Cache

LeetCode Top 100 Liked Questions 146. LRU Cache (Java版; Medium)

146. LRU Cache

146. LRU Cache(js)