Leetcode146. LRU 缓存

Every day a Leetcode

题目来源:146. LRU 缓存

解法1:哈希表 + 链表

代码:

c 复制代码
/*
 * @lc app=leetcode.cn id=146 lang=cpp
 *
 * [146] LRU 缓存
 */

// @lc code=start
class LRUCache
{
private:
    unordered_map<int, list<pair<int, int>>::iterator> hash;
    // 链表的链接顺序即为最近使用的新旧顺序,最新的信息在链表头节点
    list<pair<int, int>> cache;
    int size;

public:
    LRUCache(int capacity) : size(capacity) {}

    int get(int key)
    {
        auto it = hash.find(key);
        if (it == hash.end())
            return -1;
        // 将 it->second 从 cache 剪切到 cache 的开头
        cache.splice(cache.begin(), cache, it->second);
        return it->second->second;
    }

    void put(int key, int value)
    {
        auto it = hash.find(key);
        // 如果关键字 key 已经存在
        if (it != hash.end())
        {
            // 变更其数据值 value
            it->second->second = value;
            // 将 it->second 从 cache 剪切到 cache 的开头
            cache.splice(cache.begin(), cache, it->second);
            return;
        }
        // 向缓存中插入该组 key-value
        cache.insert(cache.begin(), make_pair(key, value));
        hash[key] = cache.begin();
        // 如果插入操作导致关键字数量超过 capacity
        if (cache.size() > size)
        {
            // 逐出最久未使用的关键字
            hash.erase(cache.back().first);
            cache.pop_back();
        }
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */
// @lc code=end

结果:

复杂度分析:

时间复杂度:O(1)。

空间复杂度:O(n),其中 n 是节点个数。

解法2:哈希表 + 自定义双向链表

代码:

c 复制代码
// 哈希表 + 自定义双向链表

class Node
{
public:
    int key, value;
    Node *prev, *next;

    Node(int k = 0, int v = 0) : key(k), value(v) {}
};

class LRUCache
{
private:
    int capacity;
    Node *dummy; // 哨兵节点
    unordered_map<int, Node *> key_to_node;

    // 删除一个节点(抽出一本书)
    void remove(Node *x)
    {
        x->prev->next = x->next;
        x->next->prev = x->prev;
    }

    // 在链表头添加一个节点(把一本书放在最上面)
    void push_front(Node *x)
    {
        x->prev = dummy;
        x->next = dummy->next;
        x->prev->next = x;
        x->next->prev = x;
    }

    Node *get_node(int key)
    {
        auto it = key_to_node.find(key);
        if (it == key_to_node.end()) // 没有这本书
            return nullptr;
        auto node = it->second; // 有这本书
        remove(node);           // 把这本书抽出来
        push_front(node);       // 放在最上面
        return node;
    }

public:
    LRUCache(int capacity) : capacity(capacity), dummy(new Node())
    {
        dummy->prev = dummy;
        dummy->next = dummy;
    }

    int get(int key)
    {
        auto node = get_node(key);
        return node ? node->value : -1;
    }

    void put(int key, int value)
    {
        auto node = get_node(key);
        if (node)
        {                        // 有这本书
            node->value = value; // 更新 value
            return;
        }
        key_to_node[key] = node = new Node(key, value); // 新书
        push_front(node);                               // 放在最上面
        if (key_to_node.size() > capacity)
        { // 书太多了
            auto back_node = dummy->prev;
            key_to_node.erase(back_node->key);
            remove(back_node); // 去掉最后一本书
            delete back_node;  // 释放内存
        }
    }
};

结果:

复杂度分析:

时间复杂度:O(1)。

空间复杂度:O(n),其中 n 是节点个数。

相关推荐
Fuyo_11195 分钟前
C++ AVL树保姆级详解:从平衡因子到四大旋转机制
java·c++·算法
傲世仙尊1 小时前
继承-类设计层次复用切片转换与菱形继承的死结
c++
架构师伯子明1 小时前
FFmpeg C++学习(一):编译和demo
开发语言·c++·学习
纪念 2292 小时前
C++算法(六)
开发语言·c++·算法
ShineWinsu2 小时前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
AI的探索之旅3 小时前
97 个 OpenCV 实例(三十七):二维码识别,一张图四个码的陷阱
c++·opencv·计算机视觉
UIU1143 小时前
P16237 [蓝桥杯 2026 省 B] 应急布线
数据结构·c++·算法·蓝桥杯
raindayinrain3 小时前
c++设计模式
开发语言·c++·设计模式
旖旎夜光3 小时前
LeetCode 315: 算右侧小于当前元素的个数(归并排序) —— 题解
c++·学习·算法·leetcode·排序算法
D e re k ZH3 小时前
保序回归:从 PAVA 到可并堆的单调约束优化
c++·算法·数据挖掘·回归·kotlin