leetcode 146. 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.
Follow up:
Could you do get and put in O(1) time complexity?

Example 1:

Input
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]

Explanation
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1); // return 1
lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2); // returns -1 (not found)
lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
lRUCache.get(1); // return -1 (not found)
lRUCache.get(3); // return 3
lRUCache.get(4); // return 4

设计一个LRU
即Least Recently Used,有get和put操作

思路:
设计一个list,把被访问过的数据提到list的head,这样慢慢的,没有访问的数据就会到tail。所以list是一个双向链表。

LRU在put的时候,如果已存数据量 > capacity,就需要删掉最近没有用过的那个,也就是tail位置的数据,把需要插入的数据插入到head。get的时候要把访问的数据移到head,表示最近刚访问过。

要在O(1)时间通过key找到value,所以需要一个HashMap。
在删掉tail位置的数据时,同时也要删掉在HashMap中对应的映射,那么要在O(1)时间通过tail部分删除的key找到HashMap中的key。所以list中要保存(key, value) pair,方便通过key找到HashMap需要删掉的key。

先利用java中的LinkedList实现

//116ms
class LRUCache {
    private int capacity;
    HashMap<Integer, Node> map = new HashMap<>();
    Deque<Node> list = new LinkedList<>();
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        if(!map.containsKey(key)) return -1;
        Node node = map.get(key);
        list.remove(node);
        list.offerFirst(node);
        
        return node.getVal();
    }
    
    public void put(int key, int value) {
        if(!map.containsKey(key)) {
            Node node = new Node(key, value);
            if(list.size() == capacity) {
                Node tmp = list.pollLast();
                map.remove(tmp.getKey());
            }
            map.put(key, node);
            list.offerFirst(node);
        } else {
            Node node = map.get(key);
            list.remove(node);  
            node.setVal(value);
            list.offerFirst(node);
        }      
    }
}

class Node{
    private int key;
    private int val;
    public Node(int key, int val) {
        this.key = key;
        this.val = val;
    }
    public void setVal(int val) {
        this.val = val;
    }
    public int getVal(){
        return this.val;
    }
    public int getKey(){
        return this.key;
    }
}

用LinkedList实现运行时间116ms,查看discuss里较快的实现都是自己实现双向链表,于是自己实现一个简易版双向链表,它主要有几个功能,插入新数据时插入到head,remove一个元素,把元素从tail移到head
自己实现版的双向链表运行时间13ms

class LRUCache {
    int capacity;
    HashMap<Integer, Node> map = new HashMap<>();
    Node head, tail;
    int size;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        head = new Node(-1, -1);
        tail = new Node(-1, -1);
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        if(!map.containsKey(key)) return -1;
        Node node = map.get(key);
        MoveToHead(node);
        return node.val;
    }
    
    public void put(int key, int value) {
       if(!map.containsKey(key)) {
           Node node = new Node(key, value);
           if(size == capacity) {
               Node tmp = popTail();
               map.remove(tmp.key);
           }
           addNodeToHead(node);
           map.put(key, node);
       } else {
           Node node = map.get(key);
           node.val = value;
           MoveToHead(node);
       }
    }
    
    void addNodeToHead(Node node) {
        //在head后面加
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;    
        size ++;
    }
    void removeNode(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
        size --;
    }
    
    void MoveToHead(Node node) {
        removeNode(node);
        addNodeToHead(node);
    }
    
    Node popTail() {
        Node node = tail.prev; //要删除的node
        removeNode(node);
        return node;
    }
}

class Node{
    int key;
    int val;
    Node prev;
    Node next;
    public Node(int key, int val) {
        this.key = key;
        this.val = val;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蓝羽飞鸟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值