LeetCode - 解题笔记 - 146 - LRU Cache

Solution 1

LRU是操作系统的主要知识点之一。

整个过程可以使用链表实现,但是考虑到要求存取都在常数时间,因此这里需要额外的调整。

  1. 查找需要使用一个额外的哈希表
  2. 链表改成一个双向链表,这样就可直接用头尾表示最近使用和最早使用页面

剩下的就是核心部分的页面替换实现了。

  • 时间复杂度: O ( 1 ) O(1) O(1),按照要求必须在常数时间内实现
  • 空间复杂度: O ( c a p a c i t y ) O(capacity) O(capacity),其中 c a p a c i t y capacity capacity为指定的缓存容量,哈希表和节点数据结构占用
class LRUNode{
    // 双向链表节点实现
public:
    int key;
    int value;
    LRUNode* prev;
    LRUNode* next;
    
    LRUNode() {
        this->key = 0;
        this->value = 0;
        this->prev = nullptr;
        this->next = nullptr;
    }
    
    LRUNode(int key, int value) {
        this->key = key;
        this->value = value;
        this->prev = nullptr;
        this->next = nullptr;
    }
};

class LRUCache {
public:
    LRUCache(int capacity) {
        // cout << "CREATE" << endl;
        this->capacity = capacity;
        this->size = 0;
        
        this->head = new LRUNode();
        this->tail = new LRUNode();
        
        this->head->next = this->tail;
        this->tail->prev = this->head;
    }
    
    int get(int key) {
        // cout << "GET" << " k:" << key << " ";
        if (this->cache.find(key) != this->cache.end()) {
            // LRU读: 访问到,直接移到头部
            // cout << "Found!" << " ";
            auto cur = this->cache[key];
            this->remove(cur);
            this->addHead(cur);
            return cur->value;
        } else {
            // LRU读:未访问到,返回-1
            // cout << "NotFound!" << " ";
            return -1;
        }
        // cout << endl;
    }
    
    void put(int key, int value) {
        // cout << "PUT" << " k:" << key << " v:" << value << " ";
        if (this->cache.find(key) != this->cache.end()) {
            // LRU写: 访问到,更新值,直接移到头部
            // cout << "Found!" << " ";
            auto cur = this->cache[key];
            cur->value = value;
            this->remove(cur);
            this->addHead(cur);
        } else {
            // LRU写:未访问到,创建节点,直接移到头部
            // cout << "NotFound!" << " ";
            auto cur = new LRUNode(key, value);
            this->cache[key] = cur;
            this->addHead(cur);
            this->size++;
            
            // LRU写:关键,如果超过了容量,去掉最后的内容
            if (this->size > this->capacity) {
                // 删节点,清表
                auto bad = this->removeTail();
                this->cache.erase(bad->key);
                this->size--;
            }
        }
        cout << endl;
    }
    
private:
    int capacity; // 容量
    int size; // 实际大小
    
    // 双线链表,head和tail表示头尾
    unordered_map<int, LRUNode*> cache;
    LRUNode* head;
    LRUNode* tail;
    
    void addHead(LRUNode* node) {
        // cout << "AddHead!" << " k:" << node->key << " v:" << node->value << " ";
        node->prev = this->head;
        node->next = this->head->next;
        
        this->head->next->prev = node;
        this->head->next = node;
    }
    
    void remove(LRUNode* node) {
        // cout << "Remove!" << " ";
        node->next->prev = node->prev;
        node->prev->next = node->next;
    }
    
    LRUNode* removeTail() {
        // cout << "RemoveTail!" << " ";
        auto node = this->tail->prev;
        this->remove(node);
        return node;
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */

Solution 2

Solution 1的Python实现

class LRUNode:
    
    def __init__(self, key=0, value=0):
        self.key = key
        self.value = value
    
        self.prev = None
        self.next = None

    
class LRUCache:

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.size = 0
    
        self.head = LRUNode()
        self.tail = LRUNode()
    
        self.head.next = self.tail
        self.tail.prev = self.head
    
        self.cache = dict()

    def get(self, key: int) -> int:
        if key in self.cache:
            cur = self.cache[key]
    
            self.remove(cur)
            self.addHead(cur)
            
            return cur.value
        else:
            return -1

    def put(self, key: int, value: int) -> None:
        if key in self.cache:
            cur = self.cache[key]
            cur.value = value
            
            self.remove(cur)
            self.addHead(cur)
        else:
            cur = LRUNode(key, value)
            self.cache[key] = cur
            self.addHead(cur)
            self.size += 1
    
            if self.size > self.capacity:
                bad = self.removeTail()
                self.cache.pop(bad.key)
                self.size -= 1
    
    def addHead(self, node):
        node.prev = self.head
        node.next = self.head.next
    
        self.head.next.prev = node
        self.head.next = node
    
    def remove(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev

    def removeTail(self):
        node = self.tail.prev
        self.remove(node)
        return node

# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)

你可能感兴趣的:(LeetCode解题笔记,leetcode,链表,数据结构)