LeetCode | LRU Cache

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指的是在满的时候删除引用最少的节点。后来才发现是按访问时间来排序的最早的节点。

读懂题意之后就比较简单了:

1. 存储数据肯定是要用map的。

2. 怎样构建这个按访问时间排序的列表呢?这个列表需要能够快速增删。链表当然就最好。如果按时间插入,那么在删除时是删除表头,增加是在表尾。

3. 插入链表时,需要把原来的节点给删掉。链表删除需要在o(1),只能用双向链表。而且当知道key的时候,需要知道当前的对应的链表节点的指针。所以map存的value可以直接设成对应的链表节点。

4.  当空间满的时候,知道了LRU的元素(表头),需要把这个元素从map中删除,所以list的节点需要知道对应的map的指针。

事后诸葛亮。。。


双头链表(doubly-linked lists)

1 record DoublyLinkedNode {

2     prev // A reference to the previous node

3     next // A reference to the next node

4     data // Data or a reference to data

5  }

6 record DoublyLinkedList {

7      DoublyLinkedNode firstNode   // points to first node of list

8       DoublyLinkedNode lastNode    // points to last node of list

9  }
1 function insertAfter(List list, Node node, Node newNode)

2      newNode.prev  := node

3      newNode.next  := node.next

4      if node.next == null

5          list.lastNode  := newNode

6      else

7          node.next.prev  := newNode

8      node.next  := newNode
1 function insertBefore(List list, Node node, Node newNode)

2      newNode.prev  := node.prev

3      newNode.next = node

4      if node.prev == null

5          list.firstNode  := newNode

6      else

7          node.prev.next  := newNode

8      node.prev  := newNode
1 function insertBeginning(List list, Node newNode)

2      if list.firstNode == null

3          list.firstNode  := newNode

4          list.lastNode   := newNode

5          newNode.prev  := null

6          newNode.next  := null

7      else

8          insertBefore(list, list.firstNode, newNode)
1 function insertEnd(List list, Node newNode)

2      if list.lastNode == null

3          insertBeginning(list, newNode)

4      else

5          insertAfter(list, list.lastNode, newNode)
 1 function remove(List list, Node node)

 2    if node.prev == null

 3        list.firstNode  := node.next

 4    else

 5        node.prev.next  := node.next

 6    if node.next == null

 7        list.lastNode  := node.prev

 8    else

 9        node.next.prev  := node.prev

10    destroy node

Circular doubly-linked lists

1 function remove(List list, Node node)

2      if node.next == node

3          list.lastNode := null

4      else

5          node.next.prev := node.prev

6          node.prev.next := node.next

7          if node == list.lastNode

8              list.lastNode := node.prev;

9      destroy node

Asymmetric doubly-linked list

同样是两个指针,next指针还是指向下一个,但是pre指针存的是自己的地址(指针的指针)。

特点:

1. 单向遍历;

2. 增删都是o(1);

3. 只要节点存在,它的prev指针一定存在。

1 function insertBefore(Node node, Node newNode)

2      if node.prev == null

3           error "The node is not in a list"

4      newNode.prev  := node.prev

5      atAddress(newNode.prev)  := newNode

6      newNode.next  := node

7      node.prev = addressOf(newNode.next)
1 function insertAfter(Node node, Node newNode)

2      newNode.next  := node.next

3      if newNode.next != null

4          newNode.next.prev = addressOf(newNode.next)

5      node.next  := newNode

6      newNode.prev  := addressOf(node.next)
1 function remove(Node node)

2      atAddress(node.prev)  := node.next

3      if node.next != null

4          node.next.prev = node.prev

5      destroy node

 

 1 class LRUCache{

 2 public:

 3     struct Data {

 4         int val;

 5         map<int, list<Data>::iterator >::iterator it;

 6     };

 7     

 8     LRUCache(int capacity) {

 9         this->capacity = capacity;

10     }

11     

12     int get(int key) {

13         map<int, list<Data>::iterator >::iterator it = keyValues.find(key);

14         if (it == keyValues.end()) {

15             return -1;

16         } else {

17             int val = it->second->val;

18             data.erase(it->second);

19             Data d;

20             d.val = val;

21             d.it = it;

22             data.push_front(d);

23             keyValues[key] = data.begin();

24             return val;

25         }

26     }

27     

28     void set(int key, int value) {

29         map<int, list<Data>::iterator >::iterator it = keyValues.find(key);

30         if (it == keyValues.end()) {

31             if (data.size() >= capacity) {

32                 keyValues.erase(data.back().it); //need to erase the map

33                 data.pop_back(); 

34             }

35             Data d;

36             d.val = value;

37             data.push_front(d);

38             keyValues[key] = data.begin();

39             data.begin()->it = keyValues.find(key);

40         } else {

41             Data d;

42             d.val = value;

43             d.it = it;

44             data.erase(it->second);

45             data.push_front(d);

46             keyValues[key] = data.begin();

47         }

48     }

49     

50 private:

51     int capacity;

52     list<Data> data;

53     map<int, list<Data>::iterator > keyValues;

54 };

 

你可能感兴趣的:(LeetCode)