[LeetCode每日一题] 146. LRU Cache

130 阅读1分钟

要实现get和put时间复杂度都为O(1),能想到的就是哈希表。由于要实现LRU,想到的就是链表,每次get/put,就把对应结点放到链表头部,同时该结点原本的prev和next都能接上,因此这条链表一定是一条双向链表。代码实现难点在于处理边界情况,即对应结点的prev或next为null时怎么处理,还有当head和tail为null时怎么处理等等。我们可以在纸上把这些情况都画一下,帮助我们在写代码时思路更清晰。

class LinkNode {
    key: number;
    val: number;
    prev: LinkNode;
    next: LinkNode;
    constructor(key:number, val:number) {
        this.key = key;
        this.val = val;
        this.prev = this.next = null;
    }
};
class LRUCache {
    head: LinkNode | null;
    tail: LinkNode | null;
    cap: number;
    key_node: Map<number,LinkNode>;
    constructor(capacity: number) {
        this.cap = capacity;
        this.key_node = new Map();
        this.head = this.tail = null;
    }

    get(key: number): number {
        if (this.key_node.has(key)) {
            let node = this.key_node.get(key);
            let prev = node.prev, next = node.next;
            if (prev) {
                prev.next = next;
                node.prev = null;
                node.next = this.head;
                this.head.prev = node;
                this.head = node;
                if (!next) this.tail = prev;
                else next.prev = prev;
            }
            return node.val;
        } else return -1;
    }

    put(key: number, value: number): void {
        if (this.key_node.has(key)) {
            let node = this.key_node.get(key);
            node.val = value;
            let prev = node.prev, next = node.next;
            if (prev) {
                prev.next = next;
                node.next = this.head;
                node.prev = null;
                this.head.prev = node;
                this.head = node;
                if (!next) this.tail = prev;
                else next.prev = prev;
            }
        } else {
            if (this.key_node.size == this.cap) {
                let node_toRemove = this.tail;
                this.key_node.delete(node_toRemove.key);
                this.tail = node_toRemove.prev;
                if (this.tail) this.tail.next = null;
                if (this.head.key == node_toRemove.key) this.head = null;
            }
            let node = new LinkNode(key, value);
            this.key_node.set(key, node);
            if (this.head) {
                node.next = this.head;
                this.head.prev = node;
                this.head = node;
            } else {
                this.head = this.tail = node;
            }
        }
    }
}