问题描述:

  设计一个LRU Cache . LRU cache 有两个操作函数。

  1.get(key)。 返回cache 中的key对应的 val 值;

  2.set(key, value)。 

  用伪代码描述如下:

if  cache中存在key  then 更新value;

else cache中不存在key

  if cache 容量超过限制 then 删除最久未访问的key

  else cache 容量未超过限制 then 插入新的key

问题分析:

  首先了解LRU原理是:优先删除最早访问的元素。(题中说的是 invalidate the least recently used item . Least 的反义词是 most , most recently 意思是最近的, 可知 least recently 意思是距离现在最远的,也就是最早的)

在不理解错题意的情况下,我们可以知道,涉及到cache中元素访问时间更新,在get 和 set都会产生。

  这道题关键是如何维护这个cache中,每个元素的访问时间。如果使用普通数组来存储每个元素的最近一次访问时间,更新操作的时间复杂度是O(1),但是查询全局最小时间的复杂度将会达到O(n))(当然这里都是指在一次set操作的情况下)。在这道题中会超时,所以这里使用了set来动态的维护每一个元素的最近一次的访问时间。因为set内部实现是一棵红黑树(也就是 平衡二叉搜索树,昨天刚刚实现了一棵二叉搜索树 好巧 今天就用到了set),所以每次更新操作(find erase insert)的时间复杂度O(log n)。最后,因为这道题的key值很小,所以可以用一个数组来哈希key值,O(1)。如果用map来哈希的话,O(log n)你会得到一个 TLE。卡常数, 我×××

ps:这道题坑爹之处 ,他把set函数定义的和STL 中set名字一模一样, 哥只能用 multiset来将就,还好这道题里有hash [key]顶着,要不就gg了。

最后代码:

class LRUCache{
public:
int cap; LRUCache(int capacity) {
memset(isInCacheMp, , sizeof isInCacheMp);
cap = capacity;
globalTick = ;
tickSet.clear();
} int get(int key) {
if(isInCacheMp[key] ){//在 cache中,更新tick
int oldTick = keyToTickMp[key];
tickSet.erase(oldTick);
keyToTickMp[key] = globalTick ++;
tickToKeyMp[keyToTickMp[key]] = key;
tickSet.insert(keyToTickMp[key]);
return keyToValMp[key];
}
else
return -;
} void set(int key, int value) {
if(isInCacheMp[key]){ //key在cache中,那么更新key的value
//更新value
keyToValMp[key] = value;
//更新tick
int oldTick = keyToTickMp[key];
tickSet.erase(oldTick);//删掉原tick
keyToTickMp[key] = globalTick ++;
tickToKeyMp[keyToTickMp[key]] = key;
tickSet.insert(keyToTickMp[key]);//更新tick
}
else{//key不在cache中,加入新key
//cout<<"tick set size is "<<tickSet.size()<<endl;
//cout<<"capacity is "<<LRUCache::cap<<endl;
if(tickSet.size() >= cap){//超过容量
//删除第一个(最小的)tick 对应的key失效
int oldTick = *tickSet.find( *tickSet.begin() );
int oldKey = tickToKeyMp[oldTick];
//cout<<"old tick "<<oldTick<<" old key is "<<oldKey<<endl;
isInCacheMp[oldKey] = ;
tickSet.erase(*tickSet.begin());
}
//插入一个新的key 以及对应的 tick
isInCacheMp[key] = ;
keyToValMp[key] = value;
keyToTickMp[key] = globalTick ++;
tickToKeyMp[keyToTickMp[key]] = key;
tickSet.insert(keyToTickMp[key]);
}
} private: int globalTick;
/*
**每一个key拥有唯一的tick 所以size也代表当前的key个数
**tick越大代表对应的key越近被使用过
*/
multiset<int> tickSet; map<int, int>keyToTickMp;//key对应的tick map<int, int>tickToKeyMp;//tick对应的key map<int, int>keyToValMp;//key对应的val //map<int, int>isInCacheMp;//记录key是否在cache中
int isInCacheMp[];
};

good luck , 加油。

吃晚饭完,回来又看了一下,突然想到 map 不就是一颗红黑树,其实完全可以代替set,这样只开一个数据结构就可以 了。然后,重写了一下。以后使用map要用标准函数,查找时用find,不要过于迷信默认的初始化值要不会引入隐形的bug.

class LRUCache{
public:
int cap;
int usedSize;
LRUCache(int capacity) {
cap = capacity;
globalTick = ;
usedSize = ;
}
int get(int key) {
globalTick ++;
if(keyToValMp.find(key) != keyToValMp.end()){//在 cache中,更新tick
int oldTick = keyToTickMp[key];
keyToTickMp[key] = globalTick;
tickToKeyMp.erase(oldTick);
tickToKeyMp[globalTick] = key;
return keyToValMp[key];
}
else
return -;
} void set(int key, int value) {
globalTick ++;
if(keyToValMp.find(key) != keyToValMp.end()){ //key在cache中,那么更新key的value
//更新value
keyToValMp[key] = value;
//更新tick
int oldTick = keyToTickMp.find(key) -> second;
keyToTickMp.erase(key);
keyToTickMp[key] = globalTick;
tickToKeyMp.erase(oldTick);
tickToKeyMp[globalTick] = key;
}
else{//key不在cache中,加入新key
if(usedSize >= cap){//超过容量
//删除第一个(最小的)tick 对应的key失效
int oldTick = tickToKeyMp.begin()->first;
int oldKey = tickToKeyMp.begin()->second;
tickToKeyMp.erase(oldTick);
keyToTickMp.erase(oldKey);
keyToValMp.erase(oldKey);
usedSize --;
}
//插入一个新的key 以及对应的 tick
keyToValMp[key] = value;
keyToTickMp[key] = globalTick;
tickToKeyMp[globalTick] = key;
usedSize ++;
}
} private: int globalTick;//全局时间滴答 map<int, int>keyToTickMp;//key对应的tick map<int, int>tickToKeyMp;//tick对应的key map<int, int>keyToValMp;//key对应的val };

【Leetcode146】LRU Cache的更多相关文章

  1. 【LeetCode】LRU Cache 解决报告

    插话:只写了几个连续的博客,博客排名不再是实际"远在千里之外"该.我们已经进入2一万内. 再接再厉.油! Design and implement a data structure ...

  2. 【leetcode】LRU Cache

    题目简述: Design and implement a data structure for Least Recently Used (LRU) cache. It should support t ...

  3. 【leetcode】LRU Cache(hard)★

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  4. 【Leetcode】 LRU Cache实现

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  5. 【LeetCode OJ】LRU Cache

    Problem Link: http://oj.leetcode.com/problems/lru-cache/ Long long ago, I had a post for implementin ...

  6. 【leetcode刷题笔记】LRU Cache

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  7. 【算法】—— LRU算法

    LRU原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”. 实现1 最常见的 ...

  8. 【Redis】LRU算法和Redis的LRU实现

    LRU原理 在一般标准的操作系统教材里,会用下面的方式来演示 LRU 原理,假设内存只能容纳3个页大小,按照 7 0 1 2 0 3 0 4 的次序访问页.假设内存按照栈的方式来描述访问时间,在上面的 ...

  9. LeetCode146:LRU Cache

    题目: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the ...

随机推荐

  1. session 与 cookie 区别-----https://segmentfault.com/a/1190000013447750?utm_source=tag-newest

    cookie数据存放在客户的浏览器上,session数据放在服务器上. cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session. sessi ...

  2. CodeForcesGym 100753E Change of Scenery

    Change of Scenery Time Limit: 10000ms Memory Limit: 262144KB This problem will be judged on CodeForc ...

  3. H5存储------localStorage和sessionStorage

    web现在随着计算机的高速发展,客户端干的事情越来越多了,随着事情的增多,很多东西存储就不止在服务器了,本地存储越来越强大了(大神原谅我废话了

  4. Ubuntu 16.04安装Adobe AIR

    安装: wget -O adobe-air.sh http://drive.noobslab.com/data/apps/AdobeAir/adobe-air.sh chmod +x adobe-ai ...

  5. Pivotal-tc-Server与Tomcat区别

    Pivotal-tc-Server之前叫做SpringSource tc Server,包含三个版本分别是:Spring版.标准版和开发版,但其中只有开发版是免费的.比如在STS中包含的版本就是开发板 ...

  6. mysql Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’

    mysql Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ 今天在linux中安装了mys ...

  7. 《WF in 24 Hours》读书笔记 - Hour 1 - Understanding Windows Workflow Foundation

    1.1 Hour 1 - Understanding Windows Workflow Foundation   1.1.1 What workflow is in general A workflo ...

  8. OpenJudge百炼习题解答(C++)--题2704:竞赛评分

    题: 总时间限制:  1000ms  内存限制:  65536kB 描写叙述 现举行一次小竞赛,參赛的3支队伍,编号为1,2,3.每支队列轮流回答问题,假设回答正确,加10分;回答错误,扣10分;放弃 ...

  9. c++中的set_new_handler和new_handler

    当operator new申请一个内存失败的时候,它会进行如下的处理步骤:    1.如果存在客户指定的处理函数,则调用处理函数(new_handler),如果不存在则抛出一个异常. 2.继续申请内存 ...

  10. Solidworks如何修改单位

    文档属性-单位-修改成mm