当前位置:   article > 正文

LFU缓存(Leetcode460)

LFU缓存(Leetcode460)
例题:

分析:

这道题可以用两个哈希表来实现,一个hash表(kvMap)用来存储节点,另一个hash表(freqMap)用来存储双向链表,链表的头节点代表最近使用的元素,离头节点越远的节点代表最近最少使用的节点。

注意:freqMap 的 key 为节点的使用频次。

下图是freqMap的结构:

这是kvMap: 它的key没有什么特殊含义,value是储存的节点

题目中调用get方法会增加元素的使用次数(freq),这时在freqMap中需要将该节点转移到对应的位置上(比如该节点使用了两次,那就把该节点转移到key为2的位置上去)

put方法分为两种情况:如果要添加的key不存在,说明是新元素,放到key为1的位置上,如果key存在,此时是修改操作,改变元素的value值,对应的频次+1,同样放到对应的位置上。

淘汰策略:要保证两个hash表中的节点数一致。

代码实现:
  1. package leetcode;
  2. import java.util.HashMap;
  3. //设计LFU缓存
  4. public class LFUCacheLeetcode460 {
  5. static class LFUCache {
  6. static class Node{
  7. Node prev;
  8. Node next;
  9. int key;
  10. int value;
  11. int freq = 1;
  12. public Node(){
  13. }
  14. public Node(int key, int value) {
  15. this.key = key;
  16. this.value = value;
  17. }
  18. }
  19. static class DoublyLinkedList{
  20. Node head;
  21. Node tail;
  22. int size;
  23. public DoublyLinkedList(){
  24. head = tail = new Node();
  25. head.next = tail;
  26. tail.prev = head;
  27. }
  28. //头部添加 head<->1<->2<->tail 添加3
  29. public void addFirst(Node node){
  30. Node oldFirst = head.next;
  31. oldFirst.prev = node;
  32. head.next = node;
  33. node.prev = head;
  34. node.next = oldFirst;
  35. size++;
  36. }
  37. //指定节点删除 head<->1<->2<->3<->tail 删除2
  38. public void remove(Node node){
  39. Node prev = node.prev;
  40. Node next = node.next;
  41. prev.next = next;
  42. next.prev = prev;
  43. size--;
  44. }
  45. //删除最后一个节点
  46. public Node removeLast(){
  47. Node last = tail.prev;
  48. remove(last);
  49. return last;
  50. }
  51. //判断双向链表是否为空
  52. public boolean isEmpty(){
  53. return size == 0;
  54. }
  55. }
  56. private HashMap<Integer,Node> kvMap = new HashMap<>();
  57. private HashMap<Integer,DoublyLinkedList> freqMap = new HashMap<>();
  58. private int capacity;
  59. private int minFreq = 1;
  60. public LFUCache(int capacity) {
  61. this.capacity = capacity;
  62. }
  63. /*
  64. * 获取节点 不存在:返回 -1
  65. * 存在: 增加节点的使用频次,将其转移到频次+1的链表中
  66. * 判断旧节点所在的链表是否为空,更新最小频次minFreq
  67. * */
  68. public int get(int key) {
  69. if(!kvMap.containsKey(key)){
  70. return -1;
  71. }
  72. Node node = kvMap.get(key);
  73. //先删除旧节点
  74. DoublyLinkedList list = freqMap.get(node.freq);
  75. list.remove(node);
  76. //判断当前链表是否为空,为空可能需要更新最小频次
  77. if(list.isEmpty() && node.freq == minFreq){
  78. minFreq++;
  79. }
  80. node.freq++;
  81. //将新节点放入新位置,可能该频次对应的链表不存在,不存在需要创建
  82. freqMap.computeIfAbsent(node.freq, k -> new DoublyLinkedList())
  83. .addFirst(node);
  84. return node.value;
  85. }
  86. /*
  87. * 更新
  88. * 将节点的value更新,增加节点的使用频次,将其转移到频次+1的链表中
  89. * 新增
  90. * 检查是否超过容量,若超过,淘汰minFreq链表的最后节点
  91. * 创建新节点,放入kvMap,并加入频次为 1 的双向链表
  92. * */
  93. public void put(int key, int value) {
  94. if(kvMap.containsKey(key)){ //更新
  95. Node node = kvMap.get(key);
  96. DoublyLinkedList list = freqMap.get(node.freq);
  97. list.remove(node);
  98. if(list.isEmpty() && node.freq == minFreq){
  99. minFreq++;
  100. }
  101. node.freq++;
  102. freqMap.computeIfAbsent(node.freq, k -> new DoublyLinkedList())
  103. .addFirst(node);
  104. node.value = value;
  105. }else{ //新增
  106. //先判断容量是否已满
  107. if(kvMap.size() == capacity){
  108. //执行淘汰策略
  109. Node node = freqMap.get(minFreq).removeLast();
  110. kvMap.remove(node.key);
  111. }
  112. Node node = new Node(key, value);
  113. kvMap.put(key, node);
  114. //加入频次为1的双向链表
  115. freqMap.computeIfAbsent(1, k -> new DoublyLinkedList())
  116. .addFirst(node);
  117. minFreq = 1;
  118. }
  119. }
  120. }
  121. public static void main(String[] args) {
  122. LFUCache cache = new LFUCache(2);
  123. cache.put(1, 1);
  124. cache.put(2, 2);
  125. System.out.println(cache.get(1)); // 1 freq=2
  126. cache.put(3, 3);
  127. System.out.println(cache.get(2)); // -1
  128. System.out.println(cache.get(3)); // 3 freq=2
  129. cache.put(4, 4);
  130. System.out.println(cache.get(1)); // -1
  131. System.out.println(cache.get(3)); // 3 freq=3
  132. System.out.println(cache.get(4)); // 4 freq=2
  133. }
  134. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/950811
推荐阅读
相关标签
  

闽ICP备14008679号