Loading

LeetCode 146. LRU 缓存机制

 

 

 

 

 

思路

哈希表 + 双向链表。在面试中,面试官一般会期望读者能够自己实现一个简单的双向链表,而不是使用语言自带的、封装好的数据结构。
 

方法一:哈希表 + C++自带的双向链表 list

 1 struct Node {
 2     int key;
 3     int value;
 4     Node(){}
 5     Node(int _key,int _value): key(_key), value(_value){}
 6 };
 7 
 8 class LRUCache {
 9 private:
10     int capacity;
11     list<Node*> cache;
12     unordered_map<int, list<Node*>::iterator> mp;
13 public:
14     LRUCache(int capacity) {
15         this->capacity = capacity;
16     }
17     
18     int get(int key) {
19         if(mp.find(key) != mp.end()) {
20             //将其更新到队头
21             Node* node = *(mp[key]);
22             cache.erase(mp[key]);
23             cache.push_front(node);
24             mp[key] = cache.begin();
25 
26             //返回对应的值    
27             return node->value;
28         } else {
29             return -1;
30         }
31     }
32     
33     void put(int key, int value) {
34         if(mp.find(key) != mp.end()) {
35             Node* node = *(mp[key]);
36             cache.erase(mp[key]);
37             node->value = value; 
38             cache.push_front(node);
39             mp[key] = cache.begin();
40         } else {
41             Node* node = new Node(key, value);
42             cache.push_front(node);
43             mp[key] = cache.begin();
44             if(cache.size() > capacity) {
45                 mp.erase(cache.back()->key);
46                 cache.pop_back();
47             }
48         }
49     }
50 };
51 
52 /**
53  * Your LRUCache object will be instantiated and called as such:
54  * LRUCache* obj = new LRUCache(capacity);
55  * int param_1 = obj->get(key);
56  * obj->put(key,value);
57  */

复杂度分析

时间复杂度:get和put都是O(1)。

 

方法二:哈希表 + 自己实现的简单双向链表

 

 1 struct DLinkedNode {
 2     int key, value;
 3     DLinkedNode* prev;
 4     DLinkedNode* next;
 5     DLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr) {}
 6     DLinkedNode(int _key, int _value): key(_key), value(_value), prev(nullptr), next(nullptr) {}
 7 };
 8 
 9 class LRUCache {
10 private:
11     unordered_map<int, DLinkedNode*> cache;
12     DLinkedNode* head;
13     DLinkedNode* tail;
14     int size;
15     int capacity;
16 
17 public:
18     LRUCache(int _capacity): capacity(_capacity), size(0) {
19         // 使用伪头部和伪尾部节点
20         head = new DLinkedNode();
21         tail = new DLinkedNode();
22         head->next = tail;
23         tail->prev = head;
24     }
25     
26     int get(int key) {
27         if (!cache.count(key)) {
28             return -1;
29         }
30         // 如果 key 存在,先通过哈希表定位,再移到头部
31         DLinkedNode* node = cache[key];
32         moveToHead(node);
33         return node->value;
34     }
35     
36     void put(int key, int value) {
37         if (!cache.count(key)) {
38             // 如果 key 不存在,创建一个新的节点
39             DLinkedNode* node = new DLinkedNode(key, value);
40             // 添加进哈希表
41             cache[key] = node;
42             // 添加至双向链表的头部
43             addToHead(node);
44             ++size;
45             if (size > capacity) {
46                 // 如果超出容量,删除双向链表的尾部节点
47                 DLinkedNode* removed = removeTail();
48                 // 删除哈希表中对应的项
49                 cache.erase(removed->key);
50                 // 防止内存泄漏
51                 delete removed;
52                 --size;
53             }
54         }
55         else {
56             // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
57             DLinkedNode* node = cache[key];
58             node->value = value;
59             moveToHead(node);
60         }
61     }
62 
63     void addToHead(DLinkedNode* node) {
64         node->prev = head;
65         node->next = head->next;
66         head->next->prev = node;
67         head->next = node;
68     }
69     
70     void removeNode(DLinkedNode* node) {
71         node->prev->next = node->next;
72         node->next->prev = node->prev;
73     }
74 
75     void moveToHead(DLinkedNode* node) {
76         removeNode(node);
77         addToHead(node);
78     }
79 
80     DLinkedNode* removeTail() {
81         DLinkedNode* node = tail->prev;
82         removeNode(node);
83         return node;
84     }
85 };

 

复杂度分析

时间复杂度:对于 put 和 get 都是 O(1)。

空间复杂度:O(capacity),因为哈希表和双向链表最多存储 capacity + 1个元素。

 

posted @ 2021-02-20 12:05  拾月凄辰  阅读(130)  评论(0编辑  收藏  举报