[JavaScript 刷题] 链表 - LRU 缓存, leetcode 146

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JavaScript 刷题] 链表 - LRU 缓存, leetcode 146相关的知识,希望对你有一定的参考价值。

[javascript 刷题] 链表 - LRU 缓存, leetcode 146

github repo 地址: https://github.com/GoldenaArcher/js_leetcode,Github 的目录 大概 会更新的更勤快一些。

题目地址:146. LRU Cache

题目

如下:

Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.

Implement the LRUCache class:

  • LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
  • int get(int key) Return the value of the key if the key exists, otherwise return -1.
  • void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.

The functions get and put must each run in O(1) average time complexity.

解题思路

这道题有这么两个限制:

  1. 删除的数据是最近没有操作过的数据
  2. 操作的时间复杂度为 O ( 1 ) O(1) O(1)

看到 O ( 1 ) O(1) O(1) 的操作时间第一个反应应该就是使用 hashtable 了,这题的两种解法都需要使用到 hashable。

Ordered Map

对于使用 JavaScript 解题,这个操作相对而言比较简单一点,毕竟 JavaScript 内置的 Map 就是 Ordered Map。其操作过程和操作原理是:

  • 每一次改查数据时,将原本的数据删除,并且重新添加到 map 中

  • 在当前数组到达 capacity 时,删除 map 中的第一个元素

    Ordered Map 的优势就在于,他迭代的顺序是按照添加的顺序进行的,因此可以完成这个需求

Hashmap + Doubly Linkedlist

这个解法里,hashmap 中的值存储的为结点,每次在操作过当前元素后,将该结点移到链表的头部。每次删除时删除链表尾部的结点。

以提供的 Example1 为例,流程如下:

  1. 两个 put 插入数据

    1 2 head tail
  2. get 一下 1,这样 1 就需要被修改到链表的头部

    断开 1, 2 和 tail 之间的连接,将 tail 和 2 连在一起

    x x x x 1 2 head tail 1 2 head tail

    同样,断开 head 和 2 之间的联系,将 1 放置在 head 后

    1 2 head tail
  3. 插入新的结点 4

    最后操作的是 2,因此需要删除 2 这个结点,将 4 放在 tail 前

  4. 重复类似操作

使用 JavaScript 解题

Ordered Map 解法

这个可以使用内置 API,代码量就会小很多。

var LRUCache = function (capacity) 
  this.capacity = capacity;
  this.cache = new Map();
;

LRUCache.prototype.get = function (key) 
  const val = this.cache.get(key);

  if (val === undefined) return -1;

  this.cache.delete(key);
  this.cache.set(key, val);

  return val;
;

LRUCache.prototype.put = function (key, value) 
  this.cache.delete(key);
  this.cache.set(key, value);

  if (this.cache.size > this.capacity) 
    for (const [key, _] of this.cache) 
      this.cache.delete(key);
      break;
    
  
;

Hashmap + Doubly Linkedlist 解法

这个相当于自己重新写了一个数据结构了,用 JavaScript 实现起来就特别的麻烦。不过 Java 内置 doubly linkedlist,如果这道题用 Java 的话会方便很多。

class Node 
  constructor(key, val) 
    this.key = key;
    this.val = val;
    this.prev = null;
    this.next = null;
  


class DLL 
  constructor() 
    this.head = new Node(-1, -1);
    this.tail = new Node(-1, -1);
    this.head.next = this.tail;
    this.tail.prev = this.head;
  

  print() 
    let l1 = this.head;
    let res = [];

    while (l1?.next) 
      res.push(l1?.val, "<->");
      l1 = l1.next;
    

    res.push(l1?.val);

    console.log(res.join(" "));
  

  appendToHead(node) 
    const next = this.head.next;
    this.head.next = node;
    node.next = next;
    next.prev = node;
    node.prev = this.head;
  

  deleteNode(node) 
    node.prev.next = node.next;
    node.next.prev = node.prev;
  

  moveToHead(node) 
    this.deleteNode(node);
    this.appendToHead(node);
  

  removeTail() 
    const node = this以上是关于[JavaScript 刷题] 链表 - LRU 缓存, leetcode 146的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode刷题模版:141 - 150

LeetCode刷题模版:141 - 150

[JavaScript 刷题] 链表 - 链表的中间结点, leetcode 876

[JavaScript 刷题] 链表 - 相交链表, leetcode 160

[JavaScript 刷题] 链表 - 相交链表, leetcode 160

[JavaScript 刷题] 链表 - 反转链表, leetcode 206