LRU算法

解析
题目

使用LinkedHashMap

  1. class LRUCache {
  2. int cap;
  3. LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
  4. public LRUCache(int capacity) {
  5. this.cap = capacity;
  6. }
  7. public int get(int key) {
  8. if (!cache.containsKey(key)) {
  9. return -1;
  10. }
  11. // 将 key 变为最近使用
  12. makeRecently(key);
  13. return cache.get(key);
  14. }
  15. public void put(int key, int val) {
  16. if (cache.containsKey(key)) {
  17. // 修改 key 的值
  18. cache.put(key, val);
  19. // 将 key 变为最近使用
  20. makeRecently(key);
  21. return;
  22. }
  23. if (cache.size() >= this.cap) {
  24. // 链表头部就是最久未使用的 key
  25. int oldestKey = cache.keySet().iterator().next();
  26. cache.remove(oldestKey);
  27. }
  28. // 将新的 key 添加链表尾部
  29. cache.put(key, val);
  30. }
  31. private void makeRecently(int key) {
  32. int val = cache.get(key);
  33. // 删除 key,重新插入到队尾
  34. cache.remove(key);
  35. cache.put(key, val);
  36. }
  37. }

不使用LinkedHashMap

  1. class LRUCache {
  2. HashMap<Integer,Node> cache;
  3. Node head;
  4. Node tail;
  5. int capacity;
  6. int size;
  7. public LRUCache(int capacity) {
  8. cache=new HashMap<>();
  9. this.capacity=capacity;
  10. this.size=0;
  11. head=new Node();
  12. tail=new Node();
  13. head.next=tail;
  14. tail.pre=head;
  15. }
  16. public int get(int key) {
  17. if(cache.containsKey(key)){
  18. Node node=cache.get(key);
  19. moveToHead(node);
  20. return node.val;
  21. }else{
  22. return -1;
  23. }
  24. }
  25. public void put(int key, int value) {
  26. if(cache.containsKey(key)){
  27. Node node=cache.get(key);
  28. node.val=value;
  29. moveToHead(node);
  30. }else{
  31. Node cur=new Node(key,value);
  32. addNode(cur);
  33. }
  34. }
  35. private void addNode(Node node){
  36. if(size==capacity){
  37. deleteOldestNode();
  38. }
  39. node.next=head.next;
  40. node.next.pre=node;
  41. node.pre=head;
  42. node.pre.next=node;
  43. size++;
  44. cache.put(node.key,node);
  45. }
  46. private void deleteOldestNode(){
  47. Node node=tail.pre;
  48. tail.pre=node.pre;
  49. tail.pre.next=tail;
  50. cache.remove(node.key);
  51. size--;
  52. }
  53. private void moveToHead(Node node){
  54. node.pre.next=node.next;
  55. node.next.pre=node.pre;
  56. node.next=head.next;
  57. node.next.pre=node;
  58. node.pre=head;
  59. head.next=node;
  60. }
  61. public class Node{
  62. int key;
  63. int val;
  64. Node pre;
  65. Node next;
  66. public Node(){}
  67. public Node(int _key,int _val){
  68. this.key=_key;
  69. this.val=_val;
  70. }
  71. }
  72. }
  73. /**
  74. * Your LRUCache object will be instantiated and called as such:
  75. * LRUCache obj = new LRUCache(capacity);
  76. * int param_1 = obj.get(key);
  77. * obj.put(key,value);
  78. */

LFU算法

解析
题目

  1. public class LFUCache {
  2. HashMap<Integer,Integer> keyToVal=new HashMap<>();
  3. HashMap<Integer,Integer> keyToFreq=new HashMap<>();
  4. HashMap<Integer, LinkedHashSet<Integer>> freqToKeys=new HashMap<>();
  5. int minFreq;
  6. int capacity;
  7. public LFUCache(int capacity) {
  8. this.capacity=capacity;
  9. this.minFreq=0;
  10. }
  11. public int get(int key) {
  12. if(!keyToVal.containsKey(key)) return -1;
  13. increaseFreq(key);
  14. return keyToVal.get(key);
  15. }
  16. public void put(int key, int value) {
  17. if(this.capacity<=0) return;
  18. if(keyToVal.containsKey(key)){
  19. keyToVal.put(key,value);
  20. increaseFreq(key);
  21. }else{
  22. if(this.capacity==keyToVal.size()) deleteKey();
  23. keyToVal.put(key,value);
  24. keyToFreq.put(key,1);
  25. freqToKeys.putIfAbsent(1,new LinkedHashSet<>());
  26. freqToKeys.get(1).add(key);
  27. this.minFreq=1;
  28. }
  29. }
  30. private void increaseFreq(int key){
  31. int freq=keyToFreq.get(key);
  32. keyToFreq.put(key,freq+1);
  33. // 将 key 加入 freq + 1 对应的列表中
  34. freqToKeys.putIfAbsent(freq+1,new LinkedHashSet<>());
  35. freqToKeys.get(freq+1).add(key);
  36. // 将 key 从 freq 对应的列表中删除
  37. LinkedHashSet<Integer> keySet=freqToKeys.get(freq);
  38. keySet.remove(key);
  39. // 如果 freq 对应的列表空了,移除这个 freq
  40. if(keySet.isEmpty()){
  41. freqToKeys.remove(freq);
  42. // 如果这个 freq 恰好是 minFreq,更新 minFreq
  43. if(freq==minFreq) minFreq++;
  44. }
  45. }
  46. private void deleteKey(){
  47. // freq 最小的 key 列表
  48. LinkedHashSet<Integer> keySet=freqToKeys.get(minFreq);
  49. // 其中最先被插入的那个 key 就是该被淘汰的 key
  50. int deletedKey=keySet.iterator().next();
  51. keySet.remove(deletedKey);
  52. if(keySet.isEmpty()) freqToKeys.remove(minFreq);
  53. //在这里不需要像increaseFreq函数里面那样去更新minFreq,因为只有在插入新值的时候,会执行delete
  54. //而插入新缓存后,put函数会更新minFreq为1
  55. keyToVal.remove(deletedKey);
  56. keyToFreq.remove(deletedKey);
  57. }
  58. }

最大频率栈

解析
题目

  1. public class FreqStack {
  2. int maxFreq;
  3. HashMap<Integer, Integer> valToFreq = new HashMap<>();
  4. HashMap<Integer, Stack<Integer>> freqToVals = new HashMap<>();
  5. public FreqStack() {
  6. this.maxFreq = 0;
  7. }
  8. public void push(int val) {
  9. int freq = valToFreq.getOrDefault(val, 0)+1;
  10. valToFreq.put(val, freq);
  11. freqToVals.putIfAbsent(freq,new Stack<>());
  12. freqToVals.get(freq).push(val);
  13. maxFreq=Math.max(maxFreq,freq);
  14. }
  15. public int pop() {
  16. Stack<Integer> stack=freqToVals.get(maxFreq);
  17. int res=stack.pop();
  18. int freq=valToFreq.get(res)-1;
  19. valToFreq.put(res,freq);
  20. if(stack.isEmpty()) maxFreq--;
  21. return res;
  22. }
  23. }