[Leetcode] LRU Cache
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and set
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.set(key, value)
- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
Solution:
数据结构
LRU的典型实现是hash map + doubly linked list
, 双向链表用于存储数据结点,并且它是按照结点最近被使用的时间来存储的。 如果一个结点被访问了, 我们有理由相信它在接下来的一段时间被访问的概率要大于其它结点。于是, 我们把它放到双向链表的头部。当我们往双向链表里插入一个结点, 我们也有可能很快就会使用到它,同样把它插入到头部。 我们使用这种方式不断地调整着双向链表,链表尾部的结点自然也就是最近一段时间, 最久没有使用到的结点。那么,当我们的Cache满了, 需要替换掉的就是双向链表中最后的那个结点(不是尾结点,头尾结点不存储实际内容)。
如下是双向链表示意图,注意头尾结点不存储实际内容:
头 --> 结 --> 结 --> 结 --> 尾
结 点 点 点 结
点 <-- 1 <-- 2 <-- 3 <-- 点
假如上图Cache已满了,我们要替换的就是结点3。
哈希表的作用是什么呢?如果没有哈希表,我们要访问某个结点,就需要顺序地一个个找, 时间复杂度是O(n)。使用哈希表可以让我们在O(1)的时间找到想要访问的结点, 或者返回未找到。
http://huntfor.iteye.com/blog/2075379
1 package POJ; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.List; 6 7 public class LRUCache { 8 private HashMap<Integer, Node> hm=new HashMap<Integer, Node>(); 9 int capacity=0; 10 Node head=new Node(); 11 Node tail=new Node(); 12 13 public LRUCache(int capacity) { 14 this.capacity=capacity; 15 head.next=tail; 16 tail.pre=head; 17 } 18 19 public int get(int key) { 20 if(hm.containsKey(key)){ 21 Node e=hm.get(key); 22 delete(e); 23 insert(head,e); 24 return e.value; 25 } 26 return -1; 27 } 28 29 public void set(int key, int value) { 30 Node e = new Node(key,value); 31 if(hm.containsKey(key)){ 32 Node exist=hm.get(key); 33 delete(exist); 34 hm.remove(key); 35 insert(head,e); 36 hm.put(key, e); 37 }else{ 38 if(hm.size()<capacity){ 39 hm.put(key, e); 40 insert(head,e); 41 }else if(hm.size()==capacity){ 42 hm.remove(tail.pre.key); 43 delete(tail.pre); 44 insert(head,e); 45 hm.put(key, e); 46 } 47 } 48 } 49 50 private void insert(Node head, Node e) { 51 // TODO Auto-generated method stub 52 e.pre=head; 53 e.next=head.next; 54 head.next=e; 55 e.next.pre=e; 56 } 57 58 private void delete(Node exist) { 59 // TODO Auto-generated method stub 60 Node pre= exist.pre; 61 Node next=exist.next; 62 pre.next=next; 63 next.pre=pre; 64 } 65 } 66 class Node{ 67 public int key; 68 public int value; 69 public Node pre; 70 public Node next; 71 public Node(){ 72 this.key=Integer.MIN_VALUE; 73 this.value=Integer.MIN_VALUE; 74 pre=null; 75 next=null; 76 } 77 public Node(int key,int value){ 78 this.key=key; 79 this.value=value; 80 pre=null; 81 next=null; 82 } 83 }