【LeetCode笔记】146. LRU缓存机制(Java、双向链表、哈希表)

文章目录

  • 题目描述
  • 思路 & 代码
      • LinkedHashMap 的写法

题目描述

  • 大名鼎鼎的超高频面试题
  • 太感动,在这道题上花了太多时间了,今天终于补上博客了TvT
    【LeetCode笔记】146. LRU缓存机制(Java、双向链表、哈希表)_第1张图片

思路 & 代码

  • 结构用的是:双向链表 + 哈希表。可以满足O(1)时间复杂度
  • put():key存在则delete,然后再put;否则直接put
  • get():key存在则保存值,然后put(放到前面,顺带删除原结点,复用代码)
  • 查找的O(1):通过HashMap实现,以及伪尾结点(removeLast)
  • 删除的O(1):通过双向链表实现
  • tips:伪头结点、伪尾结点(避免了检查相邻结点是否为null,不装入map)
class LRUCache {
	// 自己写双向链表结点类
    class DoubleListNode{
        int val;
        int key;
        DoubleListNode pre;
        DoubleListNode next;
        DoubleListNode(){}
        DoubleListNode(int keyy, int value){ key = keyy; val = value; }
    }

    int cap;
    int size;
    // 哈希表直接套用现成的 HashMap
    HashMap<Integer, DoubleListNode> map;
    // 使用伪头部、首部,便于省去判断
    DoubleListNode head,tail;

    public LRUCache(int capacity) {
        cap = capacity;
        size = 0;
        map = new HashMap();
        // 使用伪头部 & 伪首部:增删不用判断相邻为空
        // key和head、tail重复的情况怎么办:其实head和tail根本就没有放进map里
        head = new DoubleListNode();
        tail = new DoubleListNode();
        head.next = tail;
        tail.pre = head;
    }
    
    public int get(int key) {
        // 哈希查找O(1)
        DoubleListNode now = map.get(key);
        if(now != null){
            int getNum = now.val;
            // 把查找结点置于head
            put(now.key, now.val);
            return getNum;
        }
        return -1;
    }

    // 删尾 & 删中间兼容
    void removeNode(DoubleListNode removeN){
        size--;
        removeN.pre.next = removeN.next;
        removeN.next.pre = removeN.pre;
        // 记得把 map 的也删了~
        map.remove(removeN.key,removeN);
    }
    
    public void put(int key, int value) {
        // 更新的情况,删掉之前结点
        if(map.containsKey(key)){
            removeNode(map.get(key));
        }
        // 添加到head
        DoubleListNode nowN = new DoubleListNode(key, value);
        nowN.pre = head;
        nowN.next = head.next;
        head.next.pre = nowN;
        head.next = nowN;
        size++;
        // 记得加入 map~
        map.put(key,nowN);
        // Cache满,删除尾结点
        if(size > cap){
            removeNode(tail.pre);
        }
    }
}

LinkedHashMap 的写法

  • Java 自带的“外挂类”:维护插入顺序的哈希表
class LRUCache {
    private int cap;
    private Map<Integer, Integer> map = new LinkedHashMap<>();

    public LRUCache(int capacity) {
        this.cap = capacity;
    }
    
    public int get(int key) {
        if(map.keySet().contains(key)) {
            int value = map.get(key);
            map.remove(key);
            map.put(key, value);
            return value;
        }
        return -1;
    }
    
    public void put(int key, int value) {
        // Case 1: 重复插入,删除重复节点
        if(map.keySet().contains(key)) {
            map.remove(key);
        }
        // Case 2: 满了,删除第一个节点(LinkedHashMap 维护插入顺序)
        if(map.size() == cap) {
            Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
            iterator.next();
            iterator.remove();
        }
        map.put(key, value);
    }
}

你可能感兴趣的:(LeetCode要每天都刷噢,哈希表,hashmap,java,双向链表,leetcode)