Leetcode 146. LRU 缓存(Hashmap+双链表)

题目描述

请你设计并实现一个满足 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) 的平均时间复杂度运行。

测试用例

示例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

解法

解法:双链表+HashMap

HashMap:

Key Value
1 node1
2 node2

双链表:

(head)[ | ] -><- (node1)[ 1 | value1 ] -><- (node2)[ 2 | value2 ] -><- (tail)[ | ]

class LRUCache {
    /**
	  定义双向链表类
	*/
    class DoubleLinkedNode {
        int key, value;
        DoubleLinkedNode prev, next;
        DoubleLinkedNode () {
            
        }
        DoubleLinkedNode (int _key, int _value) {
            key = _key;
            value = _value;
        }
    }
    /**
      size为存放数据长度, capacity为最大缓存容量
    */
    private int size, capacity;
    /**
        双向链表头节点和尾节点
    */
    private DoubleLinkedNode head, tail;
    private Map<Integer, DoubleLinkedNode> map = new HashMap<>();
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.size = 0;
        head = new DoubleLinkedNode();
        tail = new DoubleLinkedNode();
        head.next = tail;
        tail.next = head;
    }
    
    public int get(int key){
        if (size <= 0) {
            return -1;
        }
        DoubleLinkedNode node = map.get(key);
        if (node == null) {
            // LRU中不存在元素
            return -1;
        } else {
            // LRU中存在元素
            // 将元素移到head处,表示已访问过
            moveToHead(node);
            return node.value;
        }
    }

    public void put(int key, int value) {
        // 判断是否已经存在该节点
        DoubleLinkedNode node = map.get(key);
        if (node == null) {
            // 节点为空,直接放入
            // 生成节点
            DoubleLinkedNode newNode = new DoubleLinkedNode(key, value);
            // 存放到头部, 最近访问
            addToHead(newNode);
            // map加上该节点
            map.put(key, newNode);
            size++;
            // 判断数据长度是否大于最大的LRU容量
            if (size > capacity) {
                // 移除出LRU
                DoubleLinkedNode tailRemoved = removeTail();
                // map相应移出该元素
                map.remove(tailRemoved.key);
                size--;
            }
        } else {
            // 变更数据值value
            node.value = value;
            // 移动到头部,最近访问
            moveToHead(node);
        }
    }

    private void addToHead (DoubleLinkedNode node) {
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
        node.prev = head;
    }
    /**
     移动节点到head处
    */
    private void moveToHead (DoubleLinkedNode node) {
        // 先移出
        // 前一个元素指向后一个元素
        node.prev.next = node.next;
        // 后一个元素指向前一个元素
        node.next.prev = node.prev;
        // 再放入
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
        node.prev = head;
    }

    private DoubleLinkedNode removeTail () {
        DoubleLinkedNode p = tail.prev;
        tail.prev.prev.next = tail;
        tail.prev = p.prev;
        return p;
    }
}

你可能感兴趣的:(leetcode,缓存,java)