LRU Cache------优化强迫症

最近趁着暑假刷点leetcode找点算法的感觉,按顺序依次向下刷,结果到这题就没前期那么顺利,卡了两三天。题目大意就是模拟cache内容替换的LRU算法,整个过程十分简单,难点主要在于题目本身对算法时间的严格限制。

首先应该很容易想到利用list(增删效率高)模拟cache,然后用map(查找key速度快)来形成键值对的映射。简单的数据结构选择搞定了之后就是纠结的实现过程:

1、set、get均为O(n)

我首先敲了一个set、get方法均为O(n)的想要速战速决(list存储key值,map做映射,这样每次set要使用erase方法擦掉对应key并将其添加到尾部,每次get需要find到相应的key然后再输出map[key],这里都需要遍历一遍list),结果TLE。分析一下,问题主要出在find和remove方法底层都得遍历一遍list,因此得想办法将其复杂度优化到O(1),很自然就会又祭起map这等神器。因此就过度到了如下的方法。


2、set、get均为O(1)

在1的基础上再次增加一个map容器,记录每次key值和cache块变更的迭代器位置的映射(好奇葩的思路,当时还纠结了一下能不能这么映射,结果还真可以,顿时空中飘来五只可爱的草泥马。。),这样每次需要删除和查找时就能通过key值直接定位到迭代器,因此能压缩时间复杂度。需要注意的是迭代器cache.end()需要自减后再记录,另外友情提醒一下list顺序删除时需要将erase(it)的返回值重新赋值到it以避免list断链(与本题无关)。


总结一下,设计算法首先要有一个大致的框架,确定好基本的数据结构,然后从差的复杂度逐步将其优化,这种逐步求精的过程非常令人享受。另外找时间需要总结一下stl各类容器的基本实现和方法运用,便于自己查阅和复习。附上C++代码和测试用例纪念一下回归后的第一帖

#include <iostream>
#include <map>
#include <list>

using namespace std;
class LRUCache{
      int ca;
      map<int, int> mp;
      map<int, list<int>::iterator> loc;
      
      list<int> cache;
public:
    LRUCache(int capacity) {
        ca = capacity;
        mp.clear();
        loc.clear();
        cache.clear();
    }
    
    int get(int key) {
        if (mp[key] == 0)return -1;
        if (mp[key] == -2)return 0;//若输入value为-2,则为map中有value=0的数值插入 
        if (mp[key] != -1){
           cache.erase(loc[key]);
           cache.push_back(key);
           loc[key] = --(cache.end());
        }
        return mp[key];
    }
    
    void set(int key, int value) {   
         if (mp[key] == -1 || mp[key] == 0){//如果当前key值不存在 
               if (cache.size() == ca){//若cache已满,弹出最少使用的块(list头) 
                  mp[*(cache.begin())] = -1;
                  cache.pop_front();
               }
         }
         else{//若key存在,删除后再插入到list尾部 
              cache.erase(loc[key]);     
         }
         cache.push_back(key);
         loc[key] = --(cache.end());
         if (value == 0){
            mp[key] = -2;
         }
         else
             mp[key] = value;           
    }
};
int main()
{
    LRUCache lch(2);
    char a;
    while (cin >> a){
          if (a == 's'){
             int key, value;
             cin >> key >> value;
             lch.set(key, value);      
          }      
          else {
               int key;
               cin >> key;
               cout<<"get answer:"<<lch.get(key)<<endl;;     
          }
    }
    return 0;    
}
/*
s 1 11
s 2 22
g 1
s 3 33
g 2
g 3
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值