LeetCode--LRU缓存(最近最少使用)

题目描述:
请你设计并实现一个满足 [LRU (最近最少使用) 缓存] 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

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

思路:图片源自灵茶山艾府
img

解法1:使用LinkedHashMap
代码如下:

//使用LinkedHashMap 实现LRU,
//思路:插入时,如果存在相同旧key则将旧key删除,在插入新的key value,如果不存在则直接插入。
//如果超过了容量,则删除第一个元素
private HashMap<Integer, Integer> hashMap = new LinkedHashMap<Integer, Integer>();
private int capacity;

public LRUCache(int capacity) {
    this.capacity = capacity;
}

public int get(int key) {
    //删除并重新插入
    Integer value = hashMap.remove(key);
    if (value != null) {// key 在 cache 中
        hashMap.put(key, value);// 把 key 移到链表末尾
        return value;
    }
    // key 不在 cache 中
    return -1;
}

public void put(int key, int value) {
    // 删除 key,并利用返回值判断 key 是否在 cache 中
    if (hashMap.remove(key) != null) {// key 在 cache 中
        hashMap.put(key, value);// 把 key 移到链表末尾
        return;
    }
    // key 不在 cache 中,那么就把 key 插入 cache,插入前判断 cache 是否满了
    if (hashMap.size() == capacity) {// cache 满了
        //获取最久未使用的key,keySet()返回的是一个Set,所以用iterator() 获取第一个元素
        Integer tmp = hashMap.keySet().iterator().next();
        hashMap.remove(tmp);// 移除最久未使用 key
    }
    hashMap.put(key, value);
}

解法2:手写双向链表+HashMap

代码如下:

// 双向链表
private static class Node {
    int key;
    int value;
    Node prev;
    Node next;
    public Node(int key, int value) {
        this.key = key;
        this.value = value;
    }
}
private final int capacity;
// 哨兵节点
private final Node dummy = new Node(-1, -1);
// 用于判断节点是否存在
private final HashMap<Integer, Node> map = new HashMap<>();

public LRUCache(int capacity) {
    this.capacity = capacity;
    dummy.prev = dummy;
    dummy.next = dummy;
}
public int get(int key) {
    // 获取key对应的节点
    Node node = getNode(key);
    // 如果节点不存在,则返回-1
    return node == null ? -1 : node.value;
}
public void put(int key, int value) {
    // 获取key对应的节点
    Node node = getNode(key);
    // 节点存在,则更新节点的值
    if (node != null) {
        node.value = value;
        return;
    }
    // 节点不存在,则创建节点
    node = new Node(key, value);
    // 将节点加入到map中
    map.put(key, node);
    // 将节点加入到链表头部
    pushFront(node);
    // 如果容量满了,则删除链表尾部节点
    if (map.size() > capacity) {
        // 删除链表尾部节点
        Node backNode = dummy.prev;
        // 从map中删除节点
        remove(backNode);
        map.remove(backNode.key);
    }
}
// 获取key对应的节点,同时将节点移动到链表头部
private Node getNode(int key) {
    // 如果不存在,则返回null
    if (!map.containsKey(key)) {
        return null;
    }
    // 获取节点
    Node node = map.get(key);
    // 删除节点
    remove(node);
    // 将节点移动到链表头部
    pushFront(node);
    return node;
}
// 删除节点
private void remove(Node node) {
    node.prev.next = node.next;
    node.next.prev = node.prev;
}
// 将节点插入到链表头部
private void pushFront(Node node) {
    node.next = dummy.next;
    node.prev = dummy;
    node.prev.next = node;
    node.next.prev = node;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值