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 };
原文地址:https://www.cnblogs.com/linyx/p/3666465.html