LeetCode 146. LRU Cache(LRU缓存)

时间:2022-01-26 04:46:47

原题网址:https://leetcode.com/problems/lru-cache/

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

方法:使用双向链表保存key的访问顺序,使用哈希映射来快速定位到链表的节点,以便进行移动操作。

public class LRUCache {
    private LinkNode head;
    private LinkNode tail;
    private Map<Integer, LinkNode> map;
    private int capacity;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<>(capacity);
    }
    
    public int get(int key) {
        // System.out.println("Getting " + key);
        LinkNode node = map.get(key);
        if (node == null) return -1;
        // System.out.println("Got Node(" + node.value + ")");
        if (node == tail) return node.value;
        if (node == head) {
            this.head = node.next;
            node.next.previous = null;
            node.next = null;
            this.tail.next = node;
            node.previous = this.tail;
            this.tail = node;
        } else {
            node.next.previous = node.previous;
            node.previous.next = node.next;
            node.next = null;
            node.previous = this.tail;
            this.tail.next = node;
            this.tail = node;
        }
        return node.value;
    }
    
    public void set(int key, int value) {
        // System.out.println("Setting key " + key + "= " + value);
        if (this.capacity <= 0) return;

        LinkNode node = map.get(key);
        if (node != null) {
            node.value = value;
            if (node == tail) return;
            if (node == head) {
                this.head = node.next;
                node.next.previous = null;
                node.next = null;
                this.tail.next = node;
                node.previous = this.tail;
                this.tail = node;
            } else {
                node.next.previous = node.previous;
                node.previous.next = node.next;
                node.next = null;
                node.previous = this.tail;
                this.tail.next = node;
                this.tail = node;
            }
        } else if (this.map.size() < this.capacity) {
            node = new LinkNode(key, value);
            map.put(key, node);
            if (head == null) {
                head = node;
                tail = node;
            } else {
                this.tail.next = node;
                node.previous = this.tail;
                this.tail = node;
            }
        } else {
            // System.out.println("Setting key " + key + "= " + value + ", replacing");
            node = new LinkNode(key, value);
            map.remove(this.head.key);
            map.put(key, node);
            if (this.capacity == 1) {
                // System.out.println("Setting key " + key + "= " + value + ", capacity=1");
                this.head = node;
                this.tail = node;
            } else {
                this.head.next.previous = null;
                this.head = this.head.next;
                this.tail.next = node;
                node.previous = this.tail;
                this.tail = node;
            }
        }
    }
}
class LinkNode {
    int key;
    int value;
    LinkNode previous, next;
    public LinkNode(int key, int value) {
        this.key = key;
        this.value = value;
    }
}

封装简化:

public class LRUCache {
    private Cache head = new Cache(0, 0);
    private Cache tail = new Cache(0, 0);
    {
        head.insert(tail);
    }
    private Map<Integer, Cache> map = new HashMap<>();
    private int capacity;
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        Cache cache = map.get(key);
        if (cache == null) return -1;
        cache.remove();
        cache.insert(tail);
        return cache.value;
    }
    
    public void set(int key, int value) {
        if (capacity <= 0) return;
        Cache cache = map.get(key);
        if (cache == null) {
            cache = new Cache(key, value);
            cache.insert(tail);
            if (map.size() >= capacity) {
                map.remove(head.right.key);
                head.right.remove();
            }
            map.put(key, cache);
        } else {
            cache.value = value;
            cache.remove();
            cache.insert(tail);
        }
    }
}

class Cache {
    int key, value;
    Cache left, right;
    Cache(int key, int value) {
        this.key = key;
        this.value = value;
    }
    void remove() {
        if (this.left != null) this.left.right = this.right;
        if (this.right != null) this.right.left = this.left;
        this.left = null;
        this.right = null;
    }
    void insert(Cache before) {
        this.left = before.left;
        if (this.left != null) this.left.right = this;
        
        before.left = this;
        this.right = before;
    }
}