LRU Cache -- LeetCode

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

 

题目描述如上,就是设计一个数据结构,实现LRU算法,支持两种操作,get(查询key对应的value),和set(将key,value加入集合中)

首先,我用双向链表实现,代码细节需要注意的地方较多,因为是处理指针。

  1 class LRUCache{

  2 public:

  3     class Node {

  4     public:

  5         int key, value;

  6         Node *prv, *nxt;

  7         Node():key(0), value(0), prv(NULL), nxt(NULL) {}

  8         Node(int key, int val):key(key), value(val), prv(NULL), nxt(NULL) {}

  9     };

 10     class DoubleLinkedList {

 11     public:

 12         Node *head, *tail;

 13         int size, capacity;

 14         DoubleLinkedList():size(0), capacity(0), head(NULL), tail(NULL) {}

 15         DoubleLinkedList(int c):size(0), capacity(c), head(NULL), tail(NULL) {}

 16         /*~DoubleLinkedList() {

 17             while (head != NULL) {

 18                 Node *tmp = head;

 19                 head = head->nxt;

 20                 delete tmp;

 21             }

 22         }*/

 23         void erase(Node *it) {

 24             if (size == 0) return ;

 25             if (it->prv != NULL && it->nxt != NULL) {

 26                 it->prv->nxt = it->nxt;

 27                 it->nxt->prv = it->prv;

 28             }

 29             if (it->prv == NULL) {

 30                 head = it->nxt;

 31                 if (head != NULL)

 32                     head->prv = NULL;

 33             }

 34             if (it->nxt == NULL) {

 35                 tail = it->prv;

 36                 if (tail != NULL)

 37                     tail->nxt = NULL;

 38             }

 39             size--;

 40         }

 41         int insert(Node *it) {

 42             if (tail != NULL) {

 43                 tail->nxt = it;

 44                 it->nxt = NULL;

 45                 it->prv = tail;

 46                 tail = it;

 47             } else {

 48                 head = tail = it;

 49             }

 50             //if (head == NULL) head = it;

 51             //if (tail == NULL) tail = it;

 52             size++;

 53             if (size > capacity && size > 0) {

 54                 int key = head->key;

 55                 if (size == 1) {

 56                     delete head;

 57                     head = tail = NULL;

 58                 } else {

 59                     Node *tmp = head;

 60                     head = head->nxt;

 61                     head->prv = NULL;

 62                     delete tmp;

 63                     tmp = NULL;

 64                 }

 65                 size--;

 66                 return  key;

 67             }

 68             return -1;

 69         }

 70     };

 71     LRUCache(int capacity) {

 72         //DoubleLinkedList DLL(capacity);

 73         DLL.capacity = capacity;

 74     }

 75     

 76     int get(int key) {

 77         if (HashMap.find(key) == HashMap.end()) {

 78             return -1;

 79         } else {

 80             Node *it = HashMap[key];

 81             DLL.erase(it);

 82             DLL.insert(it);

 83             return (it->value);

 84         }

 85     }

 86     

 87     void set(int key, int value) {

 88         if (HashMap.find(key) != HashMap.end()) {

 89             Node *it = HashMap[key];

 90             it->value = value;

 91             DLL.erase(it);

 92             DLL.insert(it);

 93         } else {

 94             Node *tmp = new Node(key, value);

 95             HashMap.insert(pair<int, Node*>(key, tmp));

 96             int k = DLL.insert(tmp);

 97             if (k != -1) HashMap.erase(k);

 98         }

 99     }

100     

101 private:

102     unordered_map<int, Node*> HashMap;

103     DoubleLinkedList DLL;

104 };
View Code

后来,有人说可以用list来简化代码,我原以为面试的时候应该尽量少的使用STL等高级手段,后来巨巨们说并不是这样,于是就用list实现了一遍。

 1 class LRUCache{

 2 public:

 3     LRUCache(int c) {

 4         capacity = c;

 5     }

 6     

 7     int get(int key) {

 8         int ans = -1;

 9         auto it = disc.find(key);

10         if (it != disc.end()) {

11             ans = it->second->second;

12             data.erase(it->second);

13             data.push_front(pair<int, int>(key, ans));

14             disc[key] = data.begin();

15         }

16         return ans;

17     }

18     

19     void set(int key, int value) {

20         auto it = disc.find(key);

21         if (it != disc.end()) {

22             data.erase(it->second);

23             data.push_front(pair<int, int>(key, value));

24             disc[key] = data.begin();

25         } else {

26             data.push_front(pair<int, int>(key, value));

27             disc[key] = data.begin();

28             if (data.size() > capacity) {

29                 auto it2 = data.end(); it2--;

30                 int k = it2->first;

31                 disc.erase(k);

32                 data.pop_back();

33             }

34         }

35     }

36 private:

37     unordered_map<int, list<pair<int, int> >::iterator > disc;

38     list<pair<int, int> > data; 

39     int capacity;

40 };
View Code

代码较之前短了很多,但是时间效率也是慢了一倍。

后来听说到有个东西unique_ptr,智能指针,虽然没有使用过,不过还是看了下介绍,可以省去delete操作,方便而且不容易出错。

另外,在使用list解答 本题的时候发现原来我一直没有真正理解迭代器这个概念。我们熟悉的指针也是一种迭代器,但是不可以说迭代器就是指针。

比如,数组下标也是一种迭代器,但是他就不是地址。

当使用list.erase(it)操作时,他返回的是下一个元素的迭代器,而it对应的元素已经被销毁,所以it不可以继续使用,

可以这样:

it = list.erase(it)

或者:

list.erase(it++)

下面一种方法中,在it被erase之前,已经做了一次后自增,所以此时的it是指向下一个元素的,删除了的是it之前的那个元素。

 

你可能感兴趣的:(LeetCode)