题目

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put

  • 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
  • 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:

  1. LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
  2. cache.put(1, 1);
  3. cache.put(2, 2);
  4. cache.get(1); // 返回 1
  5. cache.put(3, 3); // 该操作会使得密钥 2 作废
  6. cache.get(2); // 返回 -1 (未找到)
  7. cache.put(4, 4); // 该操作会使得密钥 1 作废
  8. cache.get(1); // 返回 -1 (未找到)
  9. cache.get(3); // 返回 3
  10. cache.get(4); // 返回 4

方案一(有序字典)

  1. from collections import OrderedDict
  2. class LRUCache:
  3. def __init__(self, capacity: int):
  4. self.capacity = capacity
  5. self._m = OrderedDict()
  6. def get(self, key: int) -> int:
  7. if key not in self._m:
  8. return -1
  9. self._m.move_to_end(key)
  10. return self._m[key]
  11. def put(self, key: int, value: int) -> None:
  12. if key in self:
  13. self.move_to_end(key)
  14. self[key] = value
  15. if len(self) > self.capacity:
  16. self.popitem(last = False)
  • 使用 python3 的 OrderedDict
  • 此处用法与队列相反,即最新的元素在队列尾部

    方案二(双向链表+hash表)

  1. class DLinkedNode:
  2. def __init__(self, key=None, val=None):
  3. self.key = key
  4. self.val = val
  5. self.prev = None
  6. self.next = None
  7. class DLinked:
  8. def __init__(self):
  9. # 使用虚拟头结点和尾节点,初始化双向链表
  10. self.head, self.tail = DLinkedNode(), DLinkedNode()
  11. self.head.next = self.tail
  12. self.tail.prev = self.head
  13. def add_node_by_val(self, key, val) -> 'DLinkedNode':
  14. '''在双向链表头部添加一个节点'''
  15. node = DLinkedNode(key, val)
  16. self.add_node(node)
  17. return node
  18. def add_node(self, node):
  19. node.prev = self.head
  20. node.next = self.head.next
  21. self.head.next.prev = node
  22. self.head.next = node
  23. def delete_node(self, node: 'DLinkedNode'):
  24. '''删除一个节点'''
  25. node.prev.next = node.next
  26. node.next.prev = node.prev
  27. def move_to_head(self, node: 'DLinkedNode'):
  28. self.delete_node(node)
  29. self.add_node(node)
  30. def delete_tail(self) -> 'DLinkedNode':
  31. '''删除尾节点'''
  32. tail = self.tail.prev
  33. self.delete_node(tail)
  34. return tail
  35. class LRUCache:
  36. def __init__(self, capacity: int):
  37. self.capacity = capacity
  38. self._cache = {} # value: node
  39. self._count = 0
  40. self.dLink = DLinked()
  41. def get(self, key: int) -> int:
  42. if key not in self._cache:
  43. return -1
  44. node = self._cache[key]
  45. self.dLink.move_to_head(node)
  46. return node.val
  47. def put(self, key: int, value: int) -> None:
  48. # 已经存在这个key则进行更新
  49. if key in self._cache:
  50. node = self._cache[key]
  51. self.dLink.delete_node(node)
  52. new_node = self.dLink.add_node_by_val(key, value)
  53. self._cache[key] = new_node
  54. return
  55. # 不存在则新增
  56. if self._count < self.capacity:
  57. self._count += 1
  58. else:
  59. tail = self.dLink.delete_tail()
  60. del self._cache[tail.key]
  61. node = self.dLink.add_node_by_val(key, value)
  62. self._cache[key] = node