zoukankan      html  css  js  c++  java
  • LeetCode(146):手写LRU算法

    LRU:最近最少使用

    题目描述

    image-20201222143944340

    算法设计

    cache这个数据结构需要具备以下条件:

    • 元素必须有时序,当容量满了以后要删除最久未使用的元素
    • get方法要求在O(1)的时间复杂度内,快速找到cache中是否存在某个key
    • 每次调用get方法,需要将被访问元素变为最近使用的,即cache要支持在O(1)的时间复杂度内插入和删除元素
    • put方法要求在O(1)的时间复杂度内,将写入数据变为最近使用的

    我们知道,哈希表支持快速查找,而链表支持快速插入和删除

    因此我们需要结合哈希表和双向链表:

    • 哈希表的key是题目提供的key,而value则是指向链表节点的指针
    • 链表中的每个节点都有key和val两个属性

    并规定:

    • 每次默认从链表尾部添加元素,越靠近尾部就越是最近使用的
    • 对于get方法,可以通过哈希表取出节点的val值
    • 对于put方法,先删除链表的第一个节点,再将其插入到链表尾部即可

    代码实现(JavaScript)

    定义节点类:

    class Node {
        constructor(k,v){
            this.key = k
            this.val = v
        }
    }
    

    定义双向链表类:

    • 构造函数:初始化两个虚拟的头尾节点
    • addLast(x):向链表尾部添加节点x
    • removeNode(x):删除链表中的节点x
    • removeFirst():删除并返回链表的第一个节点
    class DoubleList {
        constructor(){
            this.head = new Node(0,0)
            this.tail = new Node(0,0)
            this.head.next = this.tail
            this.tail.prev = this.head
            this.size = 0
        }
    
        addLast(x){
            x.prev = this.tail.prev
            x.next = this.tail
            this.tail.prev.next = x
            this.tail.prev = x
            this.size++
        }
    
        removeNode(x){
            x.prev.next = x.next
            x.next.prev = x.prev
            this.size--
        }
    
        removeFirst(){
            if(this.size === 0){
                return null
            }
            var first = this.head.next
            this.head.next = first.next
            first.next.prev = this.head
            this.size--
            return first
        }
    }
    

    定义构造函数LRUcache

    var LRUCache = function(capacity) {
        this.list = new DoubleList()
        this.map = new Map()
        this.capacity = capacity
    };
    

    编写get方法:

    • 通过map找到指定key的节点x
    • 从链表中删除节点x
    • 将节点x添加到链表尾部
    • 更新map
    • 返回节点x的val值
    LRUCache.prototype.get = function(key) {
        if(!this.map.has(key)){
            return -1
        }
        
        let tempNode = this.map.get(key)
        this.list.removeNode(tempNode)
        this.list.addLast(tempNode)
    
        this.map.set(key,tempNode)
        
        return tempNode.val
    };
    

    编写put方法:

    若key已存在:

    • 通过map找到指定key的节点x
    • 从链表中删除节点x
    • 更新节点x的val值,更新map
    • 将节点x添加到链表尾部

    若key不存在:

    • 若容量已满,删除链表第一个节点,更新map
    • 创建节点x,指定其key和val
    • 将节点x添加到链表尾部
    LRUCache.prototype.put = function(key, value) {
        if(this.map.has(key)){
            let tempNode = this.map.get(key)
            this.list.removeNode(tempNode)
            
            tempNode.val = value
            this.map.set(key,tempNode)
            this.list.addLast(tempNode)
        }else{
            if(this.list.size === this.capacity){
                let deleteNode = this.list.removeFirst()
                this.map.delete(deleteNode.key)
            }
    
            let tempNode = new Node(key,value)
            this.list.addLast(tempNode)
            this.map.set(key,tempNode)
            
        }
    };
    
  • 相关阅读:
    XAF 如何在工具栏显示多参数
    XAF Study Recources
    常用工具
    Linux下Kill函数用法
    ipv6相关转换
    宣布回归
    微软夏令营
    APEX SDK阅后感
    寻求offer,开始记录我的征程
    衣服模拟结果
  • 原文地址:https://www.cnblogs.com/baebae996/p/14173109.html
Copyright © 2011-2022 走看看