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

青岛做网站价格学网站建设

青岛做网站价格,学网站建设,网站根目录下,如何以目录形式访问网站目录 引言LRU 缓存官方解题LRU实现📌 实现步骤分解步骤 1:定义双向链表节点步骤 2:创建伪头尾节点(关键设计)步骤 3:实现链表基础操作操作 1:添加节点到头部操作 2:移除任意节点 步骤…

目录

  • 引言
  • LRU 缓存
    • 官方解题
    • LRU实现
    • 📌 实现步骤分解
      • 步骤 1:定义双向链表节点
      • 步骤 2:创建伪头尾节点(关键设计)
      • 步骤 3:实现链表基础操作
        • 操作 1:添加节点到头部
        • 操作 2:移除任意节点
      • 步骤 4:实现关键组合操作
        • 操作 3:移动节点到头部(访问时调用)
        • 操作 4:移除尾部节点(淘汰时调用)
      • 步骤 5:初始化缓存结构
      • 步骤 6:实现 get 操作
      • 步骤 7:实现 put 操作
    • 🔑 关键设计验证点
    • 🚀 完整实现代码
    • 💡 实现要点总结

请添加图片描述

  • 🙋‍♂️ 作者:海码007
  • 📜 专栏:算法专栏
  • 💥 标题:【Hot 100】 146. LRU 缓存
  • ❣️ 寄语:书到用时方恨少,事非经过不知难!

引言

这题好像几年前就是hard。后面变成medium了。感觉就是普通人只做1~2遍,都不能独立记住整个实现过程。做到第3遍时大概能记得思路开始独立写代码了,但是会遇到各种问题不能bug free的AC掉。需要练很多遍才能真的在面试中写对的。这题应该就是靠代码功底的,看能不能现场写出bug free或者能debug出来。

上面的这个是别人写的评论,看着确实是这么回事。今天能把这道题写完就算ok了。这个相当于设计一个类了。

LRU 缓存

  • 🎈 题目链接:
  • 🎈 做题状态:

官方解题

这道题涉及的知识面确实比较多,第一次做的话不容易ac。可以多写几次。

struct DLinkedNode {int key, value;DLinkedNode* prev;DLinkedNode* next;DLinkedNode() : key(0), value(0), prev(nullptr), next(nullptr) {}DLinkedNode(int _key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {}
};class LRUCache {
private:unordered_map<int, DLinkedNode*> cache;DLinkedNode* head;DLinkedNode* tail;int size;int capacity;public:LRUCache(int _capacity) : capacity(_capacity), size(0) {// 使用伪头部和伪尾部节点head = new DLinkedNode();tail = new DLinkedNode();head->next = tail;tail->prev = head;}int get(int key) {// 判断当前key是否存在if (!cache.count(key)){return -1;}// 通过哈希表快速的找到节点DLinkedNode* node = cache[key];moveToHead(node);return node->value;}void put(int key, int value) {// 判断当前key是否存在if (!cache.count(key)){// 不存在,则创建一个新节点DLinkedNode* node = new DLinkedNode(key, value);// 将其添加到哈希表中cache[key] = node;// 将新的节点添加到双向链表的头部,因为是新使用的addToHead(node);++size;// 判断当前链表大小是否超过容量,如果超出容量,则需要删除尾部节点if (size > capacity){DLinkedNode* removed = removedTail();cache.erase(removed->key);delete removed;--size;}}else{// 如果当前key存在,先通过哈希表定位,再修改value,并移动到头部DLinkedNode* node = cache[key];node->value = value;moveToHead(node);}}// 将节点添加到头部void addToHead(DLinkedNode* node){node->prev = head;node->next = head->next;head->next->prev = node;head->next = node;}// 移除节点(不释放节点内存)void removeNode(DLinkedNode* node){node->prev->next = node->next;node->next->prev = node->prev;}// 将节点移动到头部void moveToHead(DLinkedNode* node){removeNode(node);addToHead(node);}// 将移除的节点返回给外部进行处理释放DLinkedNode* removedTail(){DLinkedNode* node = tail->prev;removeNode(node);return node;}
};/*** 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);*/

LRU实现

我将把 LRU 缓存的实现拆解为 7 个清晰的步骤,并配以关键代码片段。让我们像搭积木一样逐步构建这个数据结构:


📌 实现步骤分解

步骤 1:定义双向链表节点

目的:创建存储数据的基本单元

struct Node {int key;        // 用于删除尾节点时反向查找哈希表int value;Node* prev;Node* next;Node(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {}
};

步骤 2:创建伪头尾节点(关键设计)

目的:消除边界条件判断,简化链表操作

class LRUCache {
private:Node* dummyHead; // 永远指向虚拟头部节点Node* dummyTail; // 永远指向虚拟尾部节点// 初始化伪头尾dummyHead = new Node(-1, -1);dummyTail = new Node(-1, -1);dummyHead->next = dummyTail;dummyTail->prev = dummyHead;

步骤 3:实现链表基础操作

操作 1:添加节点到头部
void addToHead(Node* node) {// 新节点的前后指针node->prev = dummyHead;node->next = dummyHead->next;// 调整原有链接dummyHead->next->prev = node;dummyHead->next = node;
}
操作 2:移除任意节点
void removeNode(Node* node) {node->prev->next = node->next;node->next->prev = node->prev;
}

步骤 4:实现关键组合操作

操作 3:移动节点到头部(访问时调用)
void moveToHead(Node* node) {removeNode(node);  // 从当前位置移除addToHead(node);   // 添加到头部
}
操作 4:移除尾部节点(淘汰时调用)
Node* removeTail() {Node* node = dummyTail->prev; // 真实尾节点removeNode(node);return node;
}

步骤 5:初始化缓存结构

class LRUCache {
private:unordered_map<int, Node*> cache; // 哈希表int capacity;                    // 容量限制public:LRUCache(int cap) : capacity(cap) {// 初始化伪头尾(见步骤2)}
};

步骤 6:实现 get 操作

int get(int key) {if (!cache.count(key)) return -1; // 未命中Node* node = cache[key];moveToHead(node);    // 更新为最近使用return node->value;
}

步骤 7:实现 put 操作

void put(int key, int value) {if (cache.count(key)) { // 已存在Node* node = cache[key];node->value = value;    // 更新值moveToHead(node);       // 设为最新} else {                   // 新增数据Node* node = new Node(key, value);cache[key] = node;      // 记录到哈希表addToHead(node);        // 添加到链表if (cache.size() > capacity) {Node* removed = removeTail();  // 淘汰最旧cache.erase(removed->key);     // 从哈希表删除delete removed;                // 释放内存}}
}

🔑 关键设计验证点

测试场景预期操作验证方法
缓存未满时插入新节点添加到头部检查链表头部是否为最新节点
缓存已满时插入淘汰尾节点后添加新节点到头部检查链表长度是否保持 capacity
访问已有节点节点被移动到头部执行get后检查节点位置
更新已有节点的值值被更新且节点移到头部检查值变化和节点位置

🚀 完整实现代码

#include <unordered_map>
using namespace std;struct Node {int key, value;Node *prev, *next;Node(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {}
};class LRUCache {
private:unordered_map<int, Node*> cache;Node *dummyHead, *dummyTail;int capacity;void addToHead(Node* node) {node->prev = dummyHead;node->next = dummyHead->next;dummyHead->next->prev = node;dummyHead->next = node;}void removeNode(Node* node) {node->prev->next = node->next;node->next->prev = node->prev;}void moveToHead(Node* node) {removeNode(node);addToHead(node);}Node* removeTail() {Node* node = dummyTail->prev;removeNode(node);return node;}public:LRUCache(int cap) : capacity(cap) {dummyHead = new Node(-1, -1);dummyTail = new Node(-1, -1);dummyHead->next = dummyTail;dummyTail->prev = dummyHead;}int get(int key) {if (!cache.count(key)) return -1;Node* node = cache[key];moveToHead(node);return node->value;}void put(int key, int value) {if (cache.count(key)) {Node* node = cache[key];node->value = value;moveToHead(node);} else {Node* node = new Node(key, value);cache[key] = node;addToHead(node);if (cache.size() > capacity) {Node* removed = removeTail();cache.erase(removed->key);delete removed;}}}
};

💡 实现要点总结

  1. 双数据结构协作

    • 哈希表:O(1) 时间查找
    • 双向链表:维护访问顺序
  2. 伪节点的妙用

    • 消除头尾节点的特殊判断
    • 统一所有节点的操作逻辑
  3. 操作原子化

    • 将链表操作分解为独立方法
    • 提高代码可读性和可维护性
  4. 内存管理

    • 淘汰节点时需手动释放内存
    • 插入新节点时动态分配内存

通过这种分步实现方式,可以更清晰地理解每个组件的作用,也便于在开发过程中逐步测试验证每个功能的正确性。

http://www.dtcms.com/wzjs/819319.html

相关文章:

  • 网址和网站的区别如何做网站大图片
  • 西安网站建设服务商网站开发人员的考核
  • win10虚拟机做网站企业英文网站建设的重要性
  • 网站图片分辨率尺寸徐州经济开发区网站
  • 萧山做网站的公司郑州it渠道网
  • 广州优质网站建设案例郑州前端培训机构排名
  • 建设网站有什么网站123cnn网址之家
  • c net 做网站好吗备案号如何绑定多个网站
  • 成都网站优化平台wordpress搜索修改
  • 无锡网站制作联系电话可以分4天做任务的网站
  • 怎么网站是谁做的网站版面特点
  • 用哪个网站做简历更好vps网站如何设置缓存
  • 企业网站html模板下载婚纱设计网站模板商城
  • 沈阳网站外包公司如何修改网页上的内容
  • 网站管理建站中国建设集团官网
  • 网站开发面试问题上海劳务派遣公司
  • 无锡建设网站网站建设用英语怎么说
  • 五华县建设工程交易中心网站个人网站做支付宝收款
  • 成都哪家做网站建设比较好wordpress百度地图插件下载
  • 查建设标准网站免费视频素材网站哪个最好
  • 重庆建设科技培训中心官方网站那个网站做logo兼职
  • 百度提交入口网站十大免费cad制图软件
  • 乐达淄博网站建设制作怎么免费搭建属于自己的网站
  • 网站设计 注意网站推广方法技巧
  • 网站如何做电脑和手机软件网站设计方案论文
  • 免费的网站加速器常德网站建设企业
  • 做网站网关备案蓝山网站建设
  • phpstudy如何搭建网站建筑公司简介范文大全
  • 福田商城网站制作网站怎么营销推广
  • 盗用别的公司网站模块乡镇网站建设方案