[LeetCode]-146.LRU Cache

题目:

为最近最少使用(LRU)缓存设计并实现了一个数据结构。它应该支持以下操作:查询和插入,并且时间复杂度为O(1)。

查询(key)-如果键存在于缓存中,则获得键值(总是正数),否则返回- 1。
插入(key,value)-如果键不存在,则插入(键,值);如果键存在,则设置键所对应的值。当缓存达到其容量时,应在插入新项之前使最近使用的项无效。

在替换旧的项时,采用LRU替换策略。将最近最少访问的项换出。

例子:

LRUCache cache = new LRUCache( 2 /* capacity */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4

解题思路:

由于要求时间复杂度为O(1),如果采用队列或数组来实现LRU,则每次插入或删除一个元素时,时间复杂度为O(n),显然不符合要求。

由于链表中元素的删除和插入时间复杂度都为O(1),因此考虑使用链表来实现LRU。链表为了插入删除方便,采用双向链表(带有头

结点,不存储任何数据)。并设置两个指针,head,tail,分别指向链表头和尾。tail指向的节点为最近访问的节点,head->next为最久

未访问的。为了使查找速度为O(1),采用hash_map(c++中现已过时,采用unordered_map替代)。其中键对应着cache中的键,用于快

速查找,值为指向链表中的节点的指针。

unordered_map<int, slist *> m;

cache中键所对应的值,存放在链表中的value中。为了在cache满时,能快速的替换旧项,在链表节点中增加一个key字段,对应着值所对应的键。

在删除时,通过该键,在unordered_map中删除该项。

(1)在查询时,如果查询的键存在,则先通过map获得该键所对应的链表中的节点,然后移除该节点,并将其插入到链表尾,并返回其值;

  如果键不存在,则直接返回-1。

(2)在插入时,分为三种情况:

  a.如果键存在,则直接将键对应的节点,移到链表尾,然后修改节点中的值。

  b.如果键不存在,并且容量未满时,为其分配节点空间,并设置其中的键和值,再将节点插入到链表尾。同时在map插入相应的键和节点指针。

  c.如果键不存在,并且容量满时,首先移除链表头的节点,然后根据节点中的key,删除map中的项,然后设置该节点的新键和新值,将其插入到链表尾,

并在map中插入相应的键和对应节点的指针。

代码如下:

 1 struct slist{
 2     int value;
 3     int key;
 4     slist *next;
 5     slist *pre;
 6     slist(int key,int value) :key(key),value(value),next(NULL),pre(NULL){}
 7     
 8 };
 9 
10 class LRUCache {
11 private:
12     int capacity;
13     slist *head;
14     slist *tail;
15     unordered_map<int, slist *> m;
16 private:
17     void push_back(slist *cur) {
18         cur->next = tail->next;
19         tail->next = cur;
20         cur->pre = tail;
21         tail = tail->next;
22     }
23     void remove(slist *cur)
24     {
25         cur->pre->next = cur->next;
26         if (cur->next != NULL)
27         {
28             cur->next->pre = cur->pre;
29             cur->next = NULL;
30         }else{
31             tail = cur->pre;
32             }
33         cur->pre = NULL;
34     }
35 public:
36     void print() {
37         slist *pos = head->next;
38         cout << "list:";
39         while (pos)
40         {
41             cout << "(" << pos->key << "," << pos->value << ")\t";
42             pos = pos->next;
43         }
44         cout <<endl;
45     }
46     LRUCache(int capacity) {
47         this->capacity = capacity;
48         head = new slist(0,0);
49         head->next = NULL;
50         head->pre = NULL;
51         tail = head;
52     }
53 
54     int get(int key) {
55         if (m.count(key) > 0)
56         {
57             slist * pos = m[key];
58             remove(pos);
59             push_back(pos);
60             return pos->value;
61         }
62         else {
63             return -1;
64         }
65     }
66 
67     void put(int key, int value) {
68         if (m.count(key) > 0)
69         {
70             slist * pos = m[key];
71             remove(pos);
72             pos->value = value;
73             push_back(pos);
74         }
75         else if (m.size()>= capacity)
76         {
77             slist *pos = head->next;
78             remove(pos);
79             m.erase(pos->key);
80             pos->key = key;
81             pos->value = value;
82             push_back(pos);
83             m.insert(pair<int,slist*>(key,pos));
84             
85         }
86         else {
87             slist *pos = new slist(key, value);
88             push_back(pos);
89             m.insert(pair<int, slist*>(key, pos));
90         }
91 
92     }
93 };

 

posted on 2018-02-07 17:04  IT_Amateur  阅读(135)  评论(0编辑  收藏  举报

导航