当前位置: 首页 > article >正文

LeetCode146. LRU 缓存(2024秋季每日一题 37)

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

示例:

输入

[“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); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

提示:

1 < = c a p a c i t y < = 3000 1 <= capacity <= 3000 1<=capacity<=3000
0 < = k e y < = 10000 0 <= key <= 10000 0<=key<=10000
0 < = v a l u e < = 1 0 5 0 <= value <= 10^5 0<=value<=105
最多调用 2 ∗ 1 0 5 2 * 10^5 2105getput


思路:双链表 + 哈希表
时间复杂度:get: O ( 1 ) O(1) O(1)、put: O ( 1 ) O(1) O(1)

  • 初始化缓存时,创建 head,tail 节点,并且相互指向彼此,初始化容器容量、容器节点数量
  • get 时:
    • 如果当前 key 存在,则将当前 key 对应的节点移到链表头部(通过 map 保存),并返回 节点的 val 值
    • 如果当前 key 不存在,则直接返回 -1
  • put 时:
    • 如果当前 key 存在,则通过 hash 表 找到对应的节点,将此节点挪到链表头部,并更新节点的 val 值
    • 如果当前 key 不存在
      • 如果链表中 当前节点数量 < 容量,则新建节点,将节点添加到链表 头部
      • 如果链表中 当前节点数量 >= 容量,则删除尾部节点,新建节点,将节点添加到 链表头部
      • 更新链表中节点 cnt 数量

map:unordered_map<int, Node *> mp;

struct Node{
    Node * pre, * ne;
    int key, val;
    Node(){
        pre = nullptr;
        ne = nullptr;
        key = 0;
        val = 0;
    }
    Node(int _key, int _val){
        key = _key, val = _val;
        pre = ne = nullptr;
    }
};
class LRUCache {
private:
    Node * head;
    Node * tail;
    unordered_map<int, Node *> mp;
    int cnt;
    int n;
public:
    LRUCache(int capacity) {
        cnt = 0;
        n = capacity;
        head = new Node();
        tail = new Node();
        head -> ne = tail;
        tail -> pre = head;
    }
    
    int get(int key) {
        if(!mp.count(key)){
            return -1;
        }
        Node * cur = mp[key];
        moveToHead(cur);
        return cur -> val;
    }
    
    void put(int key, int value) {
        if(!mp.count(key)){
            cnt++;
            Node * cur = new Node(key, value);
            if(cnt > n){
                removeTail();
                addToHead(cur);
                cnt = n;
            }else{
                addToHead(cur);
            }
            //mp[key]= cur;
            mp.insert({key, cur});
        }else{
            Node * cur = mp[key];
            cur -> val = value;
            moveToHead(cur);
        }
    }
    void removeTail(){
        mp.erase(tail -> pre -> key);
        tail -> pre = tail ->pre -> pre;
        tail -> pre -> ne = tail;
    }
    void addToHead(Node * cur){
        cur -> pre = head;
        cur -> ne = head -> ne;
        head -> ne -> pre = cur;
        head -> ne = cur;
    }
    void moveToHead(Node * cur){
        cur -> ne -> pre = cur -> pre;
        cur -> pre -> ne = cur -> ne;
        addToHead(cur);
    }
};

http://www.kler.cn/news/355661.html

相关文章:

  • Centos7 安装升级最新版Redis7.4.1
  • 《太原理工大学学报》
  • JavaGuide(9)
  • Leetcode 最长连续有效括号
  • 服务器整合:提高数据中心效率的低成本高效策略
  • Linux中安装python3.8
  • userspace 和 kernelspace
  • 【算法】力扣:复制含有随机指针节点的链表
  • Python速成笔记——知识:图像操作
  • 十三、行为型(策略模式)
  • 数据结构顺序表超详细 (通讯录相关联) 含源码 C语言
  • uniapp移动端优惠券! 附源码!!!!
  • 数据库血缘工具学习,使用以及分享
  • 状态设计模式
  • JavaScript 第20章:Web Workers
  • 设计一个高效的日志分析系统:自动检测错误日志的实用指南
  • 计算机网络架构实例
  • Rocketmq 发送消息超时踩坑,消费正常
  • AJAX——HTTP 协议请求报文和响应报文结构
  • 字节跳动青训营——入营考核解答(持续更新中~~~)