LeetCode题解
第146题 LRU缓存机制
运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | LRUCache cache = new LRUCache( 2  );
 cache.put(1, 1);
 cache.put(2, 2);
 cache.get(1);
 cache.put(3, 3);
 cache.get(2);
 cache.put(4, 4);
 cache.get(1);
 cache.get(3);
 cache.get(4);
 
 | 
原题如上,代码如下:
python版本
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 
 | class new_node:def __init__(self,key=0,value=0):
 self.key = key
 self.value = value
 self.prev = None
 self.next = None
 
 class LRUCache(object):
 def add_none(self,node):
 node.prev = self.head
 node.next = self.head.next
 self.head.next.prev = node
 self.head.next = node
 def remove_node(self,node):
 prev = node.prev
 new = node.next
 prev.next = new
 new.prev = prev
 def move_to_head(self,node):
 self.remove_node(node)
 self.add_none(node)
 def remove_last_node(self):
 last = self.tail.prev
 self.remove_node(last)
 return last
 
 def __init__(self, capacity):
 """
 :type capacity: int
 """
 self.cache = {}
 self.size = 0
 self.capacity = capacity
 self.head = new_node()
 self.tail = new_node()
 self.head.next = self.tail
 self.tail.prev = self.head
 
 def get(self, key):
 """
 :type key: int
 :rtype: int
 """
 node = self.cache.get(key)
 if not node:
 return -1
 
 self.move_to_head(node)
 return node.value
 
 def put(self, key, value):
 """
 :type key: int
 :type value: int
 :rtype: None
 """
 node = self.cache.get(key)
 if not node:
 newnode = new_node(key,value)
 self.cache[key] = newnode
 self.add_none(newnode)
 self.size += 1
 if self.size > self.capacity:
 tail = self.remove_last_node()
 del self.cache[tail.key]
 self.size -= 1
 else:
 node.value = value
 self.move_to_head(node)
 
 
 
 
 
 | 

解析:
首先,我们看到这个题所要构建的数据结构要求要在常数时间内完成get和put操作,那么可以用到哈希表,也就是python中的字典结构,辅助双向链表记录key-value信息,对于双向链表加入head和tail两个哨兵方便使用。
整体结构为:

我们先构造链表结构:
| 12
 3
 4
 5
 6
 
 | class new_node:def __init__(self,key=0,value=0):
 self.key = key
 self.value = value
 self.prev = None
 self.next = None
 
 | 
对于字典结构key值是数据结构中的key,而字典中的value是链表中的结构体Node。
在我们构造LRUcache之前,我们先得构造几种方法,并结合要求使用。
首先,LRU是最近最久未使用,我们可以用双向链表进行对使用时间进行有序排序,即最近到最久的顺序。链表中最后一个,也就是最久没有使用的那一个。
对双向链表进行维护时,会有多种情况:
- put一个key相同的key-value,我们不用管它们的value是否相同,对我们而言是要原来的key-value进行更新,我们要将原来的key-value更新后将其位置移动到第一个。这时候无论cache是否满的,都不会溢出,因为只是更新处理而已。 
- put一个新的key-value,我们会构建一个新的key-value结构体,并加入到链表中放到第一个位置,在字典中也加入新的key-value,然后判断是否溢出缓存,若溢出,那么将最久未使用也就是链表中最后一个元素删除,同时删除字典中该元素的key-value。 - 上述中我们发现我们还需要: - 
- 在链表中新加Node并放置在第一个位置: | 12
 3
 4
 5
 
 | def add_none(self,node):node.prev = self.head
 node.next = self.head.next
 self.head.next.prev = node
 self.head.next = node
 
 |  
 
- 移除old_Node: | 12
 3
 4
 5
 
 | def remove_node(self,node):prev = node.prev
 new = node.next
 prev.next = new
 new.prev = prev
 
 |  
 
- 将old_Node移动到第一个位置: | 12
 3
 
 | def move_to_head(self,node):self.remove_node(node)
 self.add_none(node)
 
 |  
 
- 将最后一个Node删除: | 12
 3
 4
 
 | def remove_last_node(self):last = self.tail.prev
 self.remove_node(last)
 return last
 
 |  
 
- 返回Node是为了使用它在字典中将它删除。 
 
- get一个key,查询其value,若没有,返回-1,若有,返回其value,并刷新使用时间,也就是将其key-value移动到链表第一个位置。 
由上述就可以构造put和get方法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | def put(self, key, value):"""
 :type key: int
 :type value: int
 :rtype: None
 """
 node = self.cache.get(key)
 if not node:
 newnode = new_node(key,value)
 self.cache[key] = newnode
 self.add_none(newnode)
 self.size += 1
 if self.size > self.capacity:
 tail = self.remove_last_node()
 del self.cache[tail.key]
 self.size -= 1
 else:
 node.value = value
 self.move_to_head(node)
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | def get(self, key):"""
 :type key: int
 :rtype: int
 """
 node = self.cache.get(key)
 if not node:
 return -1
 
 self.move_to_head(node)
 return node.value
 
 | 
同时对LRUcache的基本属性为:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | def __init__(self, capacity):"""
 :type capacity: int
 """
 self.cache = {}
 self.size = 0
 self.capacity = capacity
 self.head = new_node()
 self.tail = new_node()
 self.head.next = self.tail
 self.tail.prev = self.head
 
 |