ts算法题解(第43天)---leetcode 146.LRU缓存

227 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

前言

每天一道算法题,死磕算法

题目

请你设计并实现一个满足  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

分析

首先我们要理解什么是LRU?

LRU(least recently used)最近最少使用策略,是一种缓存淘汰策略,要注意淘汰这两个字。无论是电脑,手机,浏览器,都有一个缓存空间,但是缓存空间是有限的。当缓存空间满了的时候我们就要清楚哪些无用的缓存,保留有用的缓存。所以关键点是弄清楚什么是无用的缓存,什么是有用的缓存?

我们可以把缓存空间想象成一个队列,最近访问的放到队头,最少使用的放到队尾。

什么是有用的缓存?

LRU里面的recently就说明了什么是有用缓存,就是最近访问的数据。我们会依然保存到缓存中,并把他提升到队列的头部。

什么是无用的缓存?

LRU里面的least就说明了什么是无用缓存,就是最少访问的数据,当有新的缓存进来的时候,我们就把最少访问的数据踢出去。

用什么数据结构来保存cache数据最好?

题目中给的提示是

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

我们来分析一下什么数据结构满足这样的条件

  1. get为O(1)证明这个数据结构要有时序性,不能无序存储,比如object就不能满足有序存储的条件,object如果传入是先数字后字符串,没有时序,所以可以使用map
  2. put为O(1)就是插入速度和删除速度为O(1),我们可以使用map根据key值快速的进行插入和删除,所以这个条件map也是满足的

get(key:number)函数步骤

  • 如果cache中有key这个值
    • 那么把key所对应的value值返回
    • 删除key这条数据,重新添加
  • 如果cache中没有key这个值
    • 返回-1

put(key:number,value:number)函数步骤

  • 如果cache中有这个值
    • 删除掉,重新添加
  • 如果cache中没有这个值
    • 重新添加
  • 如果超出了capacity容量
    • 删除队尾的值

题解

class LRUCache {
  public capacity:number;
  public map:Map<any,any>;
  constructor(capacity: number) {
    this.capacity = capacity;
    this.map = new Map();
  }

  get(key: number): number {
    if(this.map.has(key)){
      let value = this.map.get(key);
      this.map.delete(key);
      this.map.set(key,value);
      return value;

    }else{
      return -1;
    }
  }

  put(key: number, value: number): void {
    if(this.map.has(key)){
      this.map.delete(key);
    }
    this.map.set(key,value);
    if(this.map.size>this.capacity){
      // 获取队头的第一个key
      let firstKey = this.map.keys().next().value;
      this.map.delete(firstKey);
    }
  }
}

总结

LRU缓存这道题目并不难,主要搞懂要使用什么数据结构做cache,才能达到好的效果

参考