数据结构与算法之链表: LeetCode 146. LRU 缓存 (Ts版)

LRU 缓存

描述

  • 请你设计并实现一个满足 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 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 1 0 5 10^5 105
  • 最多调用 2 * 1 0 5 10^5 105 次 get 和 put

Typescript 版算法实现

1 ) 方案1: 基于Map

ts 复制代码
class LRUCache {
    public cache: Map<number, any>
    public max: number
    constructor(capacity: number) {
        this.cache = new Map()
        this.max = capacity
    }

    get(key: number): number {
        if (!this.cache.has(key)) return -1
        const tmp = this.cache.get(key)
        this.cache.delete(key)
        this.cache.set(key, tmp)
        return tmp
    }

    put(key: number, value: number): void {
        if(this.cache.has(key)) {
            this.cache.delete(key)
        } else if(this.cache.size >= this.max) {
            // 新增时的淘汰机制
            this.cache.delete(this.cache.keys().next().value)
        }
        this.cache.set(key, value)
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * var obj = new LRUCache(capacity)
 * var param_1 = obj.get(key)
 * obj.put(key,value)
 */

2 ) 方案2: 哈希表 + 双向链表

ts 复制代码
class DLinkedNode {
    key: number;
    value: number;
    prev: DLinkedNode | null;
    next: DLinkedNode | null;

    constructor(key: number = 0, value: number = 0) {
        this.key = key;
        this.value = value;
        this.prev = null;
        this.next = null;
    }
}

class LRUCache {
    private size: number;
    private capacity: number;
    private cache: Map<number, DLinkedNode>;
    private head: DLinkedNode;
    private tail: DLinkedNode;

    constructor(capacity: number) {
        this.size = 0;
        this.capacity = capacity;
        this.cache = new Map();
        this.head = new DLinkedNode();
        this.tail = new DLinkedNode();
        this.head.next = this.tail;
        this.tail.prev = this.head;
    }

    private addToHead(node: DLinkedNode): void {
        node.prev = this.head;
        node.next = this.head.next;
        this.head.next!.prev = node;
        this.head.next = node;
    }

    private removeNode(node: DLinkedNode): void {
        node.prev!.next = node.next;
        node.next!.prev = node.prev;
    }

    private moveToHead(node: DLinkedNode): void {
        this.removeNode(node);
        this.addToHead(node);
    }

    private removeTail(): DLinkedNode {
        const node = this.tail.prev!;
        this.removeNode(node);
        return node;
    }

    public get(key: number): number {
        if (!this.cache.has(key)) {
            return -1;
        }
        const node = this.cache.get(key)!;
        this.moveToHead(node);
        return node.value;
    }

    public put(key: number, value: number): void {
        if (!this.cache.has(key)) {
            const newNode = new DLinkedNode(key, value);
            this.cache.set(key, newNode);
            this.addToHead(newNode);
            this.size++;
            if (this.size > this.capacity) {
                const removedNode = this.removeTail();
                this.cache.delete(removedNode.key);
                this.size--;
            }
        } else {
            const node = this.cache.get(key)!;
            node.value = value;
            this.moveToHead(node);
        }
    }
}


/**
 * Your LRUCache object will be instantiated and called as such:
 * var obj = new LRUCache(capacity)
 * var param_1 = obj.get(key)
 * obj.put(key,value)
 */
相关推荐
电子云与长程纠缠11 分钟前
UE5中制作地形材质
开发语言·缓存·ue5·编辑器·材质
z樾13 分钟前
回溯专题 记录
数据结构·算法·leetcode
MrZhangBaby1 小时前
SQL-leetcode-584. 寻找用户推荐人
数据库·sql·leetcode
凉秋girl3 小时前
Redis常见知识点
数据库·redis·缓存
serendipity_hky5 小时前
【Redis学习 | 第5篇】Redis缓存 —— 缓存的概念 + 缓存穿透 + 缓存雪崩 + 缓存击穿
java·数据库·redis·学习·缓存
黄俊懿5 小时前
【架构师从入门到进阶】第四章:前端优化思路——第三节:前置资源和缓存
前端·缓存·架构·架构师·前端优化·浏览器缓存
xiaoshiguang37 小时前
LeetCode:77. 组合
java·算法·leetcode
Ning_.11 小时前
LeetCode 第367题:有效的完全平方数
算法·leetcode·职场和发展
不玩return的马可乐13 小时前
LeetCode 747. 至少是其他数字两倍的最大数
数据结构·c++·程序人生·算法·leetcode