设计LRU缓存结构

设计LRU缓存结构

http://www.nowcoder.com/questionTerminal/e3769a5f49894d49b871c09cadd13a61

这是一道类的设计题,此类题目要求我们理解各个基本数据结构的用法及其复杂度,并且学会组合它们:

  1. 存储键值对——map/unordered_map
  2. 存储集合——set/unordered_set
  3. 查找最大/最小/topk值——大顶堆/小顶堆/平衡二叉树
  4. 序列结构——数组&链表
  5. 字符串索引——trie树(百度常考)

本题要求get和set的时间复杂度都是O(1),我们可以采用unordered_map双向链表的组合数据结构,原理如下图:

图片说明

对于两个操作的解释如下:

  • set操作
    1. 如果key存在于map中,更新value,然后把节点移到双向链表头部
    2. 如果key不在map中且没有溢出,直接构建新节点并插入链表首部
    3. 如果key不再map中但是有溢出,删除最后一个节点,再构建新节点插入链表首部
  • get操作
    1. 如果找到了,将节点移到首部并返回对应value
    2. 如果没找到,返回-1

代码如下:

//
// Created by jt on 2020/9/15.
//
#include <vector>
#include <unordered_map>
using namespace std;

struct DNode{
    DNode *pre, *next;
    int key, val;
    DNode(int k, int v): pre(nullptr), next(nullptr), key(k), val(v) {}
};

class LRUCache{
public:
    explicit LRUCache(int n): n(n){}
    int getVal(int key) {
        if (mp.count(key)) {
            setVal(key, mp[key]->val);  // 将节点移到首部
            return mp[key]->val;
        }
        else return -1;
    }
    void setVal(int key, int val) {
        if (mp.count(key)) {
            // 如果key存在,直接更新
            updateExisted(key, val);
        } else {
            // 如果key不存在,考虑缓存大小
            if (mp.size() == n) {
                // 如果缓存已满,清除最久的那个元素
                removeLast();
            }
            addFirst(key, val);
        }
    }
private:
    int n;
    unordered_map<int, struct DNode*> mp;
    struct DNode* head = nullptr, *tail = nullptr;
    void updateExisted(int key, int val) {
        mp[key]->val = val;
        if (mp[key] == head) return;
        if (mp[key] == tail) tail = mp[key]->pre;
        if (mp[key]->next) mp[key]->next->pre = mp[key]->pre;
        if (mp[key]->pre) mp[key]->pre->next = mp[key]->next;
        mp[key]->pre = nullptr;
        mp[key]->next = head;
        head->pre = mp[key];
        head = mp[key];
    }
    void removeLast() {
        int key = tail->key;
        if (tail->pre) tail->pre->next = nullptr;
        tail = tail->pre;
        delete mp[key];
        mp.erase(key);
    }
    void addFirst(int key, int val) {
        auto* tmp = new DNode(key, val);
        mp[key] = tmp;
        if (!tail && !head) { head = tail = tmp; return; }
        tmp->next = head;
        head->pre = tmp;
        head = tmp;
    }
};

class Solution {
public:
    /**
     * lru design
     * @param operators int整型vector<vector<>> the ops
     * @param k int整型 the k
     * @return int整型vector
     */
    vector<int> LRU(vector<vector<int> >& operators, int k) {
        // write code here
        LRUCache lru(k);
        vector<int> res;
        for (auto vec : operators) {
            if (vec[0] == 1) {
                lru.setVal(vec[1], vec[2]);
            } else {
                res.push_back(lru.getVal(vec[1]));
            }
        }
        return res;
    }
};
刷遍天下无敌手 文章被收录于专栏

秋招刷题历程

全部评论

相关推荐

比亚迪汽车新技术研究院 硬件工程师 总包21左右 硕士
点赞 评论 收藏
分享
点赞 评论 收藏
分享
ArisRobert:统一解释一下,第4点的意思是,公司按需通知员工,没被通知到的员工是没法去上班的,所以只要没被通知到,就自动离职。就是一种比较抽象的裁员。
点赞 评论 收藏
分享
10-30 23:23
已编辑
中山大学 Web前端
去B座二楼砸水泥地:这无论是个人素质还是专业素质都👇拉满了吧
点赞 评论 收藏
分享
5 收藏 评论
分享
牛客网
牛客企业服务