问题描述:

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

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

  2.set(key, value)。 

  用伪代码描述如下:

  1. if cache中存在key then 更新value;
  2.  
  3. else cache中不存在key
  4.  
  5.   if cache 容量超过限制 then 删除最久未访问的key
  6.  
  7.   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了。

最后代码:

  1. class LRUCache{
  2. public:
  3. int cap;
  4.  
  5. LRUCache(int capacity) {
  6. memset(isInCacheMp, , sizeof isInCacheMp);
  7. cap = capacity;
  8. globalTick = ;
  9. tickSet.clear();
  10. }
  11.  
  12. int get(int key) {
  13. if(isInCacheMp[key] ){//在 cache中,更新tick
  14. int oldTick = keyToTickMp[key];
  15. tickSet.erase(oldTick);
  16. keyToTickMp[key] = globalTick ++;
  17. tickToKeyMp[keyToTickMp[key]] = key;
  18. tickSet.insert(keyToTickMp[key]);
  19. return keyToValMp[key];
  20. }
  21. else
  22. return -;
  23. }
  24.  
  25. void set(int key, int value) {
  26. if(isInCacheMp[key]){ //key在cache中,那么更新key的value
  27. //更新value
  28. keyToValMp[key] = value;
  29. //更新tick
  30. int oldTick = keyToTickMp[key];
  31. tickSet.erase(oldTick);//删掉原tick
  32. keyToTickMp[key] = globalTick ++;
  33. tickToKeyMp[keyToTickMp[key]] = key;
  34. tickSet.insert(keyToTickMp[key]);//更新tick
  35. }
  36. else{//key不在cache中,加入新key
  37. //cout<<"tick set size is "<<tickSet.size()<<endl;
  38. //cout<<"capacity is "<<LRUCache::cap<<endl;
  39. if(tickSet.size() >= cap){//超过容量
  40. //删除第一个(最小的)tick 对应的key失效
  41. int oldTick = *tickSet.find( *tickSet.begin() );
  42. int oldKey = tickToKeyMp[oldTick];
  43. //cout<<"old tick "<<oldTick<<" old key is "<<oldKey<<endl;
  44. isInCacheMp[oldKey] = ;
  45. tickSet.erase(*tickSet.begin());
  46. }
  47. //插入一个新的key 以及对应的 tick
  48. isInCacheMp[key] = ;
  49. keyToValMp[key] = value;
  50. keyToTickMp[key] = globalTick ++;
  51. tickToKeyMp[keyToTickMp[key]] = key;
  52. tickSet.insert(keyToTickMp[key]);
  53. }
  54. }
  55.  
  56. private:
  57.  
  58. int globalTick;
  59. /*
  60. **每一个key拥有唯一的tick 所以size也代表当前的key个数
  61. **tick越大代表对应的key越近被使用过
  62. */
  63. multiset<int> tickSet;
  64.  
  65. map<int, int>keyToTickMp;//key对应的tick
  66.  
  67. map<int, int>tickToKeyMp;//tick对应的key
  68.  
  69. map<int, int>keyToValMp;//key对应的val
  70.  
  71. //map<int, int>isInCacheMp;//记录key是否在cache中
  72. int isInCacheMp[];
  73. };

good luck , 加油。

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

  1. class LRUCache{
  2. public:
  3. int cap;
  4. int usedSize;
  5. LRUCache(int capacity) {
  6. cap = capacity;
  7. globalTick = ;
  8. usedSize = ;
  9. }
  10. int get(int key) {
  11. globalTick ++;
  12. if(keyToValMp.find(key) != keyToValMp.end()){//在 cache中,更新tick
  13. int oldTick = keyToTickMp[key];
  14. keyToTickMp[key] = globalTick;
  15. tickToKeyMp.erase(oldTick);
  16. tickToKeyMp[globalTick] = key;
  17. return keyToValMp[key];
  18. }
  19. else
  20. return -;
  21. }
  22.  
  23. void set(int key, int value) {
  24. globalTick ++;
  25. if(keyToValMp.find(key) != keyToValMp.end()){ //key在cache中,那么更新key的value
  26. //更新value
  27. keyToValMp[key] = value;
  28. //更新tick
  29. int oldTick = keyToTickMp.find(key) -> second;
  30. keyToTickMp.erase(key);
  31. keyToTickMp[key] = globalTick;
  32. tickToKeyMp.erase(oldTick);
  33. tickToKeyMp[globalTick] = key;
  34. }
  35. else{//key不在cache中,加入新key
  36. if(usedSize >= cap){//超过容量
  37. //删除第一个(最小的)tick 对应的key失效
  38. int oldTick = tickToKeyMp.begin()->first;
  39. int oldKey = tickToKeyMp.begin()->second;
  40. tickToKeyMp.erase(oldTick);
  41. keyToTickMp.erase(oldKey);
  42. keyToValMp.erase(oldKey);
  43. usedSize --;
  44. }
  45. //插入一个新的key 以及对应的 tick
  46. keyToValMp[key] = value;
  47. keyToTickMp[key] = globalTick;
  48. tickToKeyMp[globalTick] = key;
  49. usedSize ++;
  50. }
  51. }
  52.  
  53. private:
  54.  
  55. int globalTick;//全局时间滴答
  56.  
  57. map<int, int>keyToTickMp;//key对应的tick
  58.  
  59. map<int, int>tickToKeyMp;//tick对应的key
  60.  
  61. map<int, int>keyToValMp;//key对应的val
  62.  
  63. };

【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. 超星toPDF

    * ssReader to pdf   Note: editor: Emacs-org   1. download and open the book with sspreader 2. click ...

  2. saltstack(三) grains、pillar的使用

    一,grains grains: 这个跟puppet的facter功能一样.主要负责采集客户端一些基本信息, 这个也完全可以自定义,可以在客户端自定义,然后自动汇报上来:也可以从服务器端定义然后推下去 ...

  3. C语言基础--数据

    c语言中数据: 在8位单片机种最常用的数据类型就是: unsigned char: 无符号字符型,位宽1个字节,8个位,表示的范围0~255(2^8-1) 在32位单片机中最常用的数据类型就是: un ...

  4. 生成随机数验证码的工具类(from韩顺平)

    生成随机数验证码的工具类 package com.cx; //生成随机数的图片 import java.awt.Color; import java.awt.Font; import java.awt ...

  5. codevs1314 寻宝

    题目描述 Description 传说很遥远的藏宝楼顶层藏着诱人的宝藏.小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书.说明书的内容如下: 藏宝楼共 ...

  6. 中间件解析FDMEMTABLE.delta生成SQL的方法

    遍历Delta.DataView.Rows,Delta.DataView.Rows是记录的行集,由行组成 TFDDatSRow,即是一行记录的对象 TFDDatSRow的方法:  GetData(), ...

  7. Android 属性动画(Property Animation) 全然解析 (上)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38067475 1.概述 Android提供了几种动画类型:View Animat ...

  8. 转:Redis 缓存策略

    转:http://api.crap.cn/index.do#/web/article/detail/web/ARTICLE/7754a002-6400-442d-8dc8-e76e72d948ac 目 ...

  9. Unity5.1 新的网络引擎UNET(十五) Networking 引用--中

    孙广东 2015.7.21 本节提供了与网络系统一起使用的组件的具体信息. 3.NetworkClient NetworkClient 是一个 HLAPI 类,管理网络连接到服务器 - - 相应着 U ...

  10. Hadoop的学习前奏(二)——Hadoop集群的配置

    前言: Hadoop集群的配置即全然分布式Hadoop配置. 笔者的环境: Linux:  CentOS 6.6(Final) x64   JDK:    java version "1.7 ...