牛客热题:设计LRU缓存结构

📟作者主页:慢热的陕西人

🌴专栏链接:力扣刷题日记

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

文章目录

牛客热题:设计LRU缓存结构

题目链接

设计LRU缓存结构_牛客题霸_牛客网 (nowcoder.com)

方法一:map+双向链表

思路

set

​ step1:查看对应的key是否已经被set过

​ step2:如果set过就将对应的节点移动到链表头,并且在哈希中改变其val的值

​ step3:如果没有set过就构建一个新的节点在哈希中创建映射,然后将新的节点插入到链表的头部

​ step4:查看缓存空间是否溢出

​ step5: 如果溢出就删除对应的链表尾部的节点,然后将哈希中的映射删除掉,并释放掉对应的节点

get

​ step1:查看是否在哈希表中出现过

​ step2:如果出现过,将其在链表中的节点移动到链表头的位置,并返回对应的val

​ step3:如果没出现过,那么直接返回-1

代码

cpp 复制代码
class Node
{
public:
    int _key;
    int _val;
    Node* _prev;
    Node* _next;
    //初始化
public:
    Node(int key, int val)
    {
        _key = key;
        _val = val;
        _prev = nullptr;
        _next = nullptr;
    }
};

class Solution {
public:
 Solution(int capacity)
 {
    size = capacity;
    head = new Node(0, 0);
    tail = new Node(0, 0);
    //将头节点和尾部节点连上
    head->_next = tail;
    tail->_prev = head;
 }
 
 int get(int key) 
 {
    if(hash.count(key))
    {
        MoveToHead(hash[key]);
        return hash[key]->_val;
    }
    else
    {
        return -1;
    } 
 }
 
 void set(int key, int value)
 {
    //1.是否已经被set过
    if(hash.count(key))
    {
        //2.将其节点移动到链表头
        MoveToHead(hash[key]);
        hash[key]->_val = value;
        cout << 2 << endl;
    }
    else 
    {
        //3.将新节点插入到链表的头部
        Node* NewNode = new Node(key, value);
        InsertToHead(NewNode);
        hash[key] = NewNode;

        //4.如果空间不够
        if(size <= 0)
        {
            //将链表尾部的节点去掉
            EraseLast();
            size++;
        }
        //5.减小空间
        size--;
    }
 }

void EraseLast()
{
    //先在哈希表中删除映射
    hash.erase(tail->_prev->_key);
    //在链表中删除
    Node* cur = tail->_prev;
    tail->_prev->_prev->_next = tail;
    tail->_prev = tail->_prev->_prev;
    delete cur;
    cur = nullptr;
}

void MoveToHead(Node* node)
{
    //已经是头部
    if(head == node->_prev)
    {
        return ;
    }
    //先将这个节点拆下来
    node->_prev->_next = node->_next;
    node->_next->_prev = node->_prev;
    
    InsertToHead(node);
}

void InsertToHead(Node* node)
{
    node->_next = head->_next;
    node->_prev = head;
    head->_next->_prev = node;
    head->_next = node;
}

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

复杂度

时间复杂度:O(1),不论是set操作还是get操作均在O(1)的时间复杂度

空间复杂度:O(N), 利用到了长度等于size+2的链表长度和对应的map

相关推荐
忍冬行者4 小时前
清理三主三从redis集群的过期key和键值超过10M的key
数据库·redis·缓存
TimberWill4 小时前
使用Redis队列优化内存队列
数据库·redis·缓存
梦里不知身是客1111 小时前
redis的缓存击穿原因
redis·缓存·bootstrap
GGBondlctrl13 小时前
【Redis】从单机架构到分布式,回溯架构的成长设计美学
分布式·缓存·架构·微服务架构·单机架构
不穿格子的程序员14 小时前
Redis篇4——Redis深度剖析:内存淘汰策略与缓存的三大“天坑”
数据库·redis·缓存·雪崩·内存淘汰策略
想搞艺术的程序员18 小时前
Go语言环形队列:原理剖析、编程技巧与核心优势
后端·缓存·golang
T1ssy18 小时前
深入解析Redis三大缓存问题:穿透、击穿、雪崩及解决方案
数据库·redis·缓存
木易 士心18 小时前
NestJS 核心揭秘:InstanceWrapper 的艺术与前端缓存新思路
前端·缓存
Haooog18 小时前
Redis面试题(不定时更新)
数据库·redis·缓存·面试
孙同学_18 小时前
【Linux篇】线程互斥、同步与线程池设计:原理与实践
数据库·redis·缓存