Bootstrap

leetcode 146. LRU缓存机制

leetcode 146. LRU缓存机制

题目详情

题目链接
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥已经存在,则变更其数据值;如果密钥不存在,则插入该组「密钥/数据值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

  • 进阶:
    你是否可以在 O(1) 时间复杂度内完成这两种操作?
  • 示例:
    LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
    cache.put(1, 1);
    cache.put(2, 2);
    cache.get(1); // 返回 1
    cache.put(3, 3); // 该操作会使得密钥 2 作废
    cache.get(2); // 返回 -1 (未找到)
    cache.put(4, 4); // 该操作会使得密钥 1 作废
    cache.get(1); // 返回 -1 (未找到)
    cache.get(3); // 返回 3
    cache.get(4); // 返回 4

我的代码

class LRUCache {
private:
    int capacity, cur;
    map<int, int> datas;
    list<int> keys;
    map<int, list<int>::iterator> locs;
public:
    LRUCache(int capacity) {
        this->capacity = capacity, cur = 0;
    }
    
    int get(int key) {
        if (!datas.count(key)) {
            return -1;
        }
        keys.erase(locs[key]);
        keys.push_back(key);
        locs[key] = --keys.end();
        return datas[key];
    }
    
    void put(int key, int value) {
        if (datas.count(key)) {
            keys.erase(locs[key]);
            keys.push_back(key);
            locs[key] = --keys.end();
        } else if (cur < capacity) {
            ++cur;
            keys.push_back(key);
            locs[key] = --keys.end();
        } else {
            keys.push_back(key);
            locs[key] = --keys.end();
            datas.erase(keys.front());
            keys.erase(keys.begin());
        }
        datas[key] = value;
    }
};

/**
 * 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);
 */

我的成绩

执行结果:通过
执行用时 : 588 ms, 在所有 C++ 提交中击败了5.03%的用户
内存消耗 : 36.8 MB, 在所有 C++ 提交中击败了100.00%的用户

一些想法

本道题我使用了一个map和一个数组,map用来记录key和alue,数组用来记录key的位置,并在set和put时做相应的更新。

执行用时为 0 ms 的范例

struct  bid_ListNode {
    bid_ListNode* next;
    bid_ListNode* last;
    int val;
    int key;
    bid_ListNode(int key, int value):key(key),val(value), next(NULL), last(NULL){};
};

class LRUCache {
    int cap =0;
    bid_ListNode* head = NULL;
    bid_ListNode* tail = NULL;
    unordered_map<int, bid_ListNode*> index;
    int current_cap = 0;


    // 从链表里删除,必定存在
    void remove(bid_ListNode* ptr) {
        bid_ListNode* pre = ptr->last;
        bid_ListNode* nex = ptr->next;
        pre->next = nex;
        nex->last = pre;
    }

    // 插入新的在末尾
    void insert_tail(bid_ListNode* ptr){
        bid_ListNode* pre = tail->last;
        pre ->next = ptr;
        ptr->next = tail;
        ptr->last = pre;
        tail->last = ptr;
    }
public:
    LRUCache(int capacity) {
        cap = capacity;
        current_cap = 0;
        // 初始化链表
        if(capacity ==0)
            return ;
        head = new bid_ListNode(0,0);
        tail = new bid_ListNode(0,0);
        tail->last = head;
        head->next = tail;  
    }
    
    int get(int key) {
        if(index.find(key) == index.end())
            return -1;
        bid_ListNode* ptr = index[key];
        //更新ptr的
        put(ptr->key, ptr->val);
        return ptr->val;
    }
    
    void put(int key, int value) {
        // 当前存在,更新key, 插到表头
        if(index.find(key) != index.end()) {
            bid_ListNode* ptr = index[key];
            ptr->val = value;
            // 从中间删除
            remove(ptr);
            //插在末尾
            insert_tail(ptr);
        } else {
            bid_ListNode* ptr = new bid_ListNode(key,value);
            index[key] = ptr;
             // 当前不存在,还没有满,插入在末尾
            if(current_cap < cap){
                //插在末尾
                insert_tail(ptr);
                current_cap ++;
            } else {
             // 当前不存在,满了
                //删除头部,包括index
                bid_ListNode* curr_head = head->next;
                index.erase(curr_head->key);
                remove(curr_head);
                //插入尾部
                insert_tail(ptr);
            }
        }

       
    }
};

/**
 * 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);
 */

思考

范例用了链表,使得在做更新时可以减少更新时间。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;