零 题目:算法(leetcode,附思维导图 + 全副解法)300题之(146)LRU 缓存

一 题目形容


二 解法总览(思维导图)

三 全副解法

1 计划1

1)代码:

// 计划1 “本人。哈希法”。// 技巧:遇到 O(1) 的get、put操作,优先思考 哈希表(JS里的Map数据结构)。/** * @param {number} capacity */var LRUCache = function(capacity) {    this.capacity = capacity;    this.curCapacity = 0;    // 注:越是最近应用的key,就越往 map 的前面放!    this.map = new Map();};/**  * @param {number} key * @return {number} */LRUCache.prototype.get = function(key) {    const {map} = this;    let resVal = -1;        // 边界1:get操作,若 曾经有该key,    // 则 先删该key、接着把该key放到map的最初 —— 示意最近应用过该key!    if (map.has(key)) {        resVal = map.get(key);        map.delete(key);        map.set(key, resVal);    }        return resVal;};/**  * @param {number} key  * @param {number} value * @return {void} */LRUCache.prototype.put = function(key, value) {    const {capacity, curCapacity, map} = this;    // 边界2:put操作,若 曾经有该key,    // 则 先删该key、接着把该key放到map的最初 —— 示意最近应用过该key!    if (map.has(key)) {        map.delete(key);        map.set(key, value);        return;    }    // 边界3:put操作,若 以后曾经放不下了(即 curCapacity >= capacity ),    // 则 删除map的第一个key 且 将新key放到map的最初 —— 示意最近应用过该key!    if (curCapacity >= capacity) {        for (const [key, val] of map) {            map.delete(key);            break;        }        map.set(key, value);    }    // 边界4:put操作,若 以后放得下(即 curCapacity < capacity ),    // 则 间接将新key放到map的最初 —— 示意最近应用过该key 且 this.curCapacity++ 。    else {        map.set(key, value);        this.curCapacity++;    }    // 注:以上 5行 ,能够合并成如下 2行 (但为了可读性,可分拆为 if、else 2分支):    // }    // map.set(key, value);};

2 计划2

1)代码:

// 计划2 “本人。哈希表 + 双向链表”。// 参考:// 1)https://leetcode.cn/problems/lru-cache/solution/146-lru-huan-cun-ji-zhi-by-chen-wei-f-tl1n/// 思路:// 1)重点实现 ListNode 和 LRUCache 2个类。// 2)get、put操作:// 依据当前情况进行 curCapacity、map、各种节点 的信息变更即可,详见代码的实现。//双向链表的单个节点class ListNode {    constructor(key, value) {        this.key = key;        this.value = value;        //指向后一个节点        this.next = null;        //指向前一个节点        this.prev = null;    }}class LRUCache {    constructor(capacity) {        this.capacity = capacity;        this.curCapacity = 0;        this.map = new Map();        this.dummyHead = new ListNode();        this.dummyTail = new ListNode();        this.dummyHead.next = this.dummyTail;        this.dummyTail.prev = this.dummyHead;    }    get(key) {        const {map = new Map()} = this,            node = map.get(key);                // 没找到        if (!node) {            return - 1;        }        // 找到,将该节点挪到头部,并返回相应的值        this.moveToHead(node);        return node.value;    }    put(key, value) {        const {map = new Map()} = this,            node = map.get(key);                if (!node) {            // 不存在该节点,则进行节点的创立。            const newNode = new ListNode(key, value);            map.set(key, newNode);            // 退出头结点(addToHead),而不是挪(moveToHead)            this.addToHead(newNode);            this.curCapacity++;            // 边界:超容量了,得删除            if (this.curCapacity > this.capacity) {                this.removeLRUItem();            }        }        else {            // 存在该节点,更新其值 并 将该节点挪到头部            node.value = value;            this.moveToHead(node);        }    }    moveToHead(node) {        //从链表中删除该节点 并 将该节点增加至头结点        this.removeFromList(node);        this.addToHead(node);    }    // 节点的删除(实质:指针指向的变更)    removeFromList(node) {        let nodePre = node.prev,            nodeNext = node.next;                nodePre.next = nodeNext;        nodeNext.prev = nodePre;    }    // 节点退出链表头部 的指针操作    addToHead(node) {        const {dummyHead = null} = this,            dummyHeadNext = dummyHead.next;        node.prev = dummyHead;        node.next = dummyHeadNext;        dummyHeadNext.prev = node;        dummyHead.next = node;        // 注:下面4行代码等价于上面1行(JS的语法糖)        // [node.prev, node.next, dummyHeadNext.prev, dummyHead.next] = [dummyHead, dummyHeadNext, node, node];    }    removeLRUItem() {        const {dummyTail = null, map = new Map()} = this,            tailNode = dummyTail.prev;                // 删除尾结点 并更新容量(即 curCapacity )信息        this.removeFromList(tailNode);        map.delete(tailNode.key);        this.curCapacity--;    }}

四 资源分享 & 更多

1 历史文章 - 总览

2 博主简介

码农三少 ,一个致力于编写 极简、但齐全题解(算法) 的博主。
专一于 一题多解、结构化思维 ,欢送一起刷穿 LeetCode ~