Recently I read some interviews. LruCache, as a classic medium algorithm, is often asked to tear by hand in interviews. Interviewers often ask interviewees to optimize the algorithm to improve efficiency. Two designs are available.

Note: Most interviewers will not let candidates use Java’s internal implementation classes, so LinkedHashMap is not considered in this article.

1.LinkedList+HashMap

Ideas:

public class LruCache {		
    private int capacity;	
    private HashMap<Integer, Integer> map;	
    private LinkedList<Integer> list;		
    public LruCache(int capacity) {		
        this.capacity=capacity;		
        this.map=new HashMap<>();		
        this.list=new LinkedList<>();	
    }		
    public int get(int key) {		
        if(!map.containsKey(key))return -1;		
        list.remove((Integer)key);		
        list.addLast(key);		
        return map.get(key);	
    }		
    public void put(int key,int value) {		
        if(map.size()==capacity) {			
        map.remove(list.getFirst());            
        list.removeFirst();		
        }		
        if(!map.containsKey(key)){			
            map.put(key, value);			        
            list.addLast(key);		
        }else {			
            map.put(key, value);			
            list.remove((Integer)key);
            list.addLast(key);		
        }
    }

}
Copy the code
Execution Result:
Execution time: 177 ms, beating 25.84% of users in all Java commits
Memory consumption: 47.8MB, beating 66.45% of all Java commits

2.HashMap+ custom bidirectional node:

Ideas:

class LRUCache { int capacity; HashMap<Integer,LruNode> map; LruNode first; LruNode first; LruNode last; public LRUCache(int capacity) { this.capacity=capacity; map=new HashMap<>(); The first = new LruNode (1, 0); The last = new LruNode (1, 0); first.next=last; last.pre=first; } public int get(int key) { if(! map.containsKey(key))return -1; LruNode node=map.get(key); deleteNode(node); updateLast(node); map.put(key,node); return node.value; } public void put(int key,int value) { if(map.containsKey(key)){ LruNode node= map.get(key); deleteNode(node); updateLast(node); node.value=value; map.put(key,node); }else{ if(map.size()==capacity){ LruNode temp=first.next; first.next=temp.next; temp.next.pre=first; map.remove(temp.key,temp); LruNode node=new LruNode(key,value); updateLast(node); map.put(key,node); }else{ LruNode node=new LruNode(key,value); updateLast(node); map.put(key,node); } } } public void updateLast(LruNode node) { last.pre.next=node; node.pre=last.pre; node.next=last; last.pre=node; } public void deleteNode(LruNode node) { node.pre.next=node.next; node.next.pre=node.pre; } class LruNode{ int key; int value; LruNode pre; LruNode next; public LruNode(int key,int value){ this.value=value; this.key=key; }}}Copy the code
Execution Result:
Execution time: 33 ms, beating 70.72% of all Java commits
Memory consumption: 47.6 MB, beating 81.07% of all Java commits

Execution results with inner classes fall somewhere in between:

Execution time: 40 ms, beating 39.43% of all Java commits
Memory consumption: 48.2 MB, beating 18.71% of all Java commits

No method has been found that is more efficient than the second one, and other ideas will continue to be added.