【Leetcode】146. LRU Cache

题目地址:

https://leetcode.com/problems/lru-cache/

设计一个数据结构作为Least Recently Used Cache。它可以实现下面的操作:
1、get(key),得到key对应的value(题目保证得到的value一定是正数)。如果对应的key不存在,则返回 − 1 −1 1
2、set(key, value),如果cache里不存在这样的key,就添加进去;否则就将key对应的value设成参数value;
3、cache有容量限制,当存储的数据超过容量限制的时候,要按照最近一次使用的时间最早的顺序将其删除。”使用“包括get和set。

可以用双向链表 + 哈希表的方法来做。链表的作用是存储key和value,哈希表的作用是存储key和key对应的node。

具体的方法是,如果要get某个值时,先去哈希表里查这个值有没有,没有直接返回-1,否则得到这个key对应的节点,然后删除掉那个对应的节点,接着在链表头新建一个对应节点的拷贝,这样就达到了“最近get过的节点都在头,最近没get过的节点都在链表尾”的效果,一旦到了capacity,就直接把链表尾部节点删掉即可。

如果要put某个值时,做法和get类似,也是要先查一下有没有那个key,没有的话直接在表头加,否则也是把中间那个node删掉再在表头新建一个拷贝。

注:
链表里可以只放value不放key吗?答案是不可以。因为在超过capacity的时候需要删除首个结点的时候,只知道其value无法知道其key,就无法在哈希表里删除对应的key。

代码如下:

class LRUCache {
 public:
  struct ListNode {
    ListNode *prev, *next;
    int key, val;
    ListNode(int key, int val) {
      this->key = key;
      this->val = val;
      prev = next = nullptr;
    }
  };
  using node_p = ListNode*;
  node_p head, tail;
  node_p nn(int key, int val) { return new ListNode(key, val); }
  unordered_map<int, node_p> mp;
  int sz, cap;

  LRUCache(int capacity) {
    cap = capacity;
    sz = 0;
    head = nn(0, 0), tail = nn(0, 0);
    head->next = tail, tail->prev = head;
  }

  node_p delink(node_p node) {
    if (node->next) node->next->prev = node->prev;
    if (node->prev) node->prev->next = node->next;
    return node;
  }

  void move_to_head(node_p node) {
    delink(node);
    node->next = head->next, node->prev = head;
    head->next = node, node->next->prev = node;
  }

  int get(int key) {
    if (!mp.count(key)) return -1;
    auto node = mp[key];
    move_to_head(node);
    return node->val;
  }

  void put(int key, int value) {
    if (mp.count(key)) {
      auto node = mp[key];
      node->val = value;
      move_to_head(node);
    } else {
      sz++;
      move_to_head(nn(key, value));
      mp[key] = head->next;
      if (sz > cap) {
        mp.erase(delink(tail->prev)->key);
        sz--;
      }
    }
  }
};

所有操作时间复杂度 O ( 1 ) O(1) O(1),空间 O ( k ) O(k) O(k) k k k是容量。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值