CodeTop-146-LRU缓存

题目

题目链接:146. LRU 缓存 - 力扣(LeetCode)

请你设计并实现一个满足  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.使用哈希表存储key到Node的映射关系

        2.使用双链表存储数据的LRU顺序

对于操作:

1.对于Get

首先看cache里有没有,有则返回value,同时将这个节点移到链表头部,已表明最近使用过。

moveToHead可以分为两步,一步删除节点removeNode,一步将节点添加到头部addToHead

2.对于Put

首先看cache里有没有,有则更新node的值,同时将他移动到头部。

如果没有,就新建Node加入到 头部,同时更新cache和size,每次插入要记得判断size是否超过了capacity,超过了则要按照LRU淘汰。

按照我们的规则,那么双链表尾部的节点就是最近最久未使用的Node,删除即可。删除又可以使用removeNode直接实现。

代码

type LRUCache struct {
    capacity int
    size int
    cache map[int]*Node
    head *Node
    tail *Node
}

type Node struct{
    key,value int
    prev,next *Node
}


func Constructor(capacity int) LRUCache {
    l := LRUCache{
        capacity:capacity,
        cache: make(map[int]*Node),
        head: &Node{},
        tail: &Node{},
    }

    l.head.next = l.tail
    l.tail.prev = l.head
    return l
}


func (this *LRUCache) Get(key int) int {
    if node,ok := this.cache[key];ok{
        this.moveToHead(node)
        return node.value
    }
    return -1
}


func (this *LRUCache) Put(key int, value int)  {
    if node,ok := this.cache[key];ok{
        node.value = value
        this.moveToHead(node)
    }else{
        node := &Node{key:key,value:value}
        this.addToHead(node)
        this.cache[key]=node
        this.size++
        if this.size>this.capacity{
            removed := this.removeTail()
            delete(this.cache,removed.key)
            this.size--
        }
    }
}

func (this *LRUCache) moveToHead(node *Node){
    this.removeNode(node)
    this.addToHead(node)
}

func (this *LRUCache) removeNode(node *Node){
    node.prev.next = node.next
    node.next.prev = node.prev
}

func (this *LRUCache) addToHead(node *Node){
    node.prev = this.head
    node.next = this.head.next
    this.head.next.prev = node
    this.head.next = node
}

func (this *LRUCache) removeTail() *Node{
    removed := this.tail.prev
    this.removeNode(this.tail.prev)
    return removed
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ivan陈哈哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值