leetcode 147 LRU

在这里插入图片描述
本题其实就是需要实现LRU算法,并且要求复杂度是O(1),所以我们就需要结合数据结构来思考,我们可以采用双向链表+哈希表的结构,通过hashmap的key添加元素key,value添加双向链表的节点,其中节点用来存储题中给的值。这样就能满足复杂度要求了。

关于LRU算法,可以参考灵茶山艾府的讲解,非常通俗易懂。
在这里插入图片描述
在这里插入图片描述

这里需要注意,如果我们要添加元素,首先需要判断容量是否够,如果不够,则需要删除最底下的书,如果够则需要判断是否已经存在这本书,如果不存在直接添加,存在则需要把之前的书给覆盖掉。
如果我们要查询书,直接查询hashmap,如果里面有则返回这本书,并且把这本书放到最上面,如果没有返回-1即可。

题目中的dummy节点其实就是双向链表的虚拟头节点,可以说通过它把双向链表变成了双向循环链表!这样就方便我们的操作了。

public class LRUCache {

    private static class Node {//定义链表类
        int key, value;//因为我们在删除最后一次使用的数据的时候,需要知道key才可以。
        Node prev, next;

        Node(int k, int v) {
            key = k;
            value = v;
        }
    }

    private final int capacity;
    private final Node dummy = new Node(0, 0); // 哨兵节点(虚拟节点)
    private final Map<Integer, Node> keyToNode = new HashMap<>();

    public LRUCache(int capacity) {
        this.capacity = capacity;
        dummy.prev = dummy;//虚拟节点初始化,一开始其前后指针都指向自己
        dummy.next = dummy;
    }

    public int get(int key) {
        Node node = getNode(key);
        return node != null ? node.value : -1;
    }

    public void put(int key, int value) {
        Node node = getNode(key);
        if (node != null) { // 有这本书
            node.value = value; // 更新 value
            return;
        }
        node = new Node(key, value); // 新书
        keyToNode.put(key, node);
        pushFront(node); // 放在最上面
        if (keyToNode.size() > capacity) { // 书太多了
            Node backNode = dummy.prev;
            keyToNode.remove(backNode.key);
            remove(backNode); // 去掉最后一本书
        }
    }

    private Node getNode(int key) {
        if (!keyToNode.containsKey(key)) { // 没有这本书
            return null;
        }
        Node node = keyToNode.get(key); // 有这本书
        remove(node); // 把这本书抽出来
        pushFront(node); // 放在最上面
        return node;
    }

    // 删除一个节点(抽出一本书)
    private void remove(Node x) {
        x.prev.next = x.next;//当前节点的后节点指向当前节点的前指针的后指针
        x.next.prev = x.prev;
    }

    // 在链表头添加一个节点(把一本书放在最上面)
    private void pushFront(Node x) {
        x.prev = dummy;
        x.next = dummy.next;
        x.prev.next = x;//不可以把x.prev换成dummy,因为dummy是虚拟节点,x.prev应该是真实存在的节点
        x.next.prev = x;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值