Leetcode 题目

https://leetcode-cn.com/problems/lru-cache/submissions/

方法一 双端链表+hashmap、

get和put的时间复杂度都是o(1) 所以使用hashmap 这种数据结构来做
为了(1)的时间复杂度就获取头节点和尾部节点, 以及增加和删除方便,所以使用了双端链表, 删除的时候就是该节点的上一个指向了该节点的下一个。所以使用双端链表可以方便的知道该节点的上一个和下一个。

  1. /**
  2. * 最近最少使用 并没有统计次数 只要用了就放到前面 如何统计最热 就是使用次数最多的?
  3. */
  4. public class LRUCache {
  5. class DLinkedNode {
  6. int key;
  7. int value;
  8. DLinkedNode prev;
  9. DLinkedNode next;
  10. }
  11. /*
  12. 永远添加到头部
  13. 双向队列如果插入一个元素要记得赋值俩次
  14. */
  15. private void addNode(DLinkedNode newNode) {
  16. DLinkedNode oldHead = head.next;
  17. head.next = newNode;
  18. newNode.prev = head;
  19. oldHead.prev = newNode;
  20. newNode.next = oldHead;
  21. }
  22. /**
  23. *
  24. * @param node
  25. * 删除节点永远是要去删除队尾的节点
  26. */
  27. private void removeNode(DLinkedNode node){
  28. DLinkedNode prev = node.prev;
  29. DLinkedNode next = node.next;
  30. prev.next = next;
  31. next.prev = prev;
  32. }
  33. private HashMap<Integer, DLinkedNode> cache =
  34. new HashMap<Integer, DLinkedNode>();
  35. private int capacity;
  36. private DLinkedNode head, tail;
  37. public LRUCache(int capacity) {
  38. this.capacity = capacity;
  39. head = new DLinkedNode();
  40. // head.prev = null;
  41. tail = new DLinkedNode();
  42. // tail.next = null;
  43. head.next = tail;
  44. tail.prev = head;
  45. }
  46. public int get(int key) {
  47. DLinkedNode node = cache.get(key);
  48. if (node == null) return -1;
  49. //因为这就算使用了,所以要添加到头部。可以拆分成方法,把下面俩个包含进去
  50. removeNode(node);
  51. addNode(node);
  52. return node.value;
  53. }
  54. public void put(int key, int value) {
  55. DLinkedNode node = cache.get(key);
  56. //如果取出的是空节点 说明key不存在,如果存在则把该节点移动到头部
  57. if(node == null) {
  58. DLinkedNode newNode = new DLinkedNode();
  59. newNode.key = key;
  60. newNode.value = value;
  61. //在map中保存key
  62. cache.put(key, newNode);
  63. addNode(newNode);
  64. //如果节点超出个数 那么删除尾部节点
  65. if(cache.size() > capacity) {
  66. // pop the tail
  67. cache.remove(tail.prev.key);
  68. removeNode(tail.prev);
  69. }
  70. } else {
  71. // 更新数据的方式就是先删后增
  72. removeNode(node);
  73. node.value = value;
  74. addNode(node);
  75. }
  76. }
  77. }

方法2、继承LinkedHashMap 都是操作父类。

  1. class LRUCache extends LinkedHashMap<Integer, Integer> {
  2. private int capacity;
  3. public LRUCache(int capacity) {
  4. super(capacity, 0.75F, true);
  5. this.capacity = capacity;
  6. }
  7. public int get(int key) {
  8. return super.getOrDefault(key, -1);
  9. }
  10. public void put(int key, int value) {
  11. super.put(key, value);
  12. }
  13. @Override
  14. protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
  15. return size() > capacity;
  16. }
  17. }

后记

如何统计最热 就是使用次数最多的?LFU?LRU-k?

参考

https://blog.csdn.net/zhanglong_4444/article/details/88344953
https://leetcode-cn.com/problems/lru-cache/solution/lru-huan-cun-ji-zhi-by-leetcode/