LeetCode 146. LRU Cache
原题链接在这里:https://leetcode.com/problems/lru-cache/
题目:
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and put
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.put(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.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // returns 1 cache.put(3, 3); // evicts key 2 cache.get(2); // returns -1 (not found) cache.put(4, 4); // evicts key 1 cache.get(1); // returns -1 (not found) cache.get(3); // returns 3 cache.get(4); // returns 4
题解:
可以通过HashMap 和 Double LinkedList来完成。每个key, value用一个Node 来储存,按照添加顺序一个一个放在list 的head后面。同时把<key, node>放在HashMap中。
get时看HashMap中是否有这个key, 有的话就找到对应的node, 在node里取出对应的value. 同时更新该node 在list中的位置。
set时分三种情况:1. 看HashMap中是否有这个key, 有的话说明本来就有这个key对应的node, 只需要把原有node的value更改并且更新该node 在list中位置即可。
2. HashMap中没有这个key, 同时HashMap的size未达到capacity, 那么新建一个node, 加入HashMap 和 list中即可。
3. HashMap中没有这个key, 同时HashMap的size已经等于capacity, 多加就要溢出,所以按照2中完成添加后要从HashMap 和 list中都去掉最老的node.
Time Complexity: get, O(1). put O(1).
Space: O(n).
AC Java:
1 class Node{ 2 int key; 3 int val; 4 Node prev; 5 Node next; 6 public Node(int key, int val){ 7 this.key = key; 8 this.val = val; 9 } 10 } 11 12 class LRUCache { 13 Node head; 14 Node tail; 15 Map<Integer, Node> hm; 16 int capacity; 17 18 public LRUCache(int capacity) { 19 head = new Node(-1, -1); 20 tail = new Node(1, 1); 21 head.next = tail; 22 tail.prev = head; 23 this.capacity = capacity; 24 hm = new HashMap<>(); 25 } 26 27 public int get(int key) { 28 if(!hm.containsKey(key)){ 29 return -1; 30 } 31 32 Node target = hm.get(key); 33 putToHead(target); 34 return target.val; 35 } 36 37 public void put(int key, int value) { 38 if(hm.containsKey(key)){ 39 Node cur = hm.get(key); 40 cur.val = value; 41 putToHead(cur); 42 return; 43 } 44 45 if(hm.size() >= capacity){ 46 int lastKey = removeOldest(); 47 hm.remove(lastKey); 48 } 49 50 Node addedNode = new Node(key, value); 51 hm.put(key, addedNode); 52 putToHead(addedNode); 53 } 54 55 private void putToHead(Node cur){ 56 if(cur.prev != null && cur.next != null){ 57 cur.prev.next = cur.next; 58 cur.next.prev = cur.prev; 59 } 60 61 cur.next = head.next; 62 cur.prev = head; 63 head.next.prev = cur; 64 head.next = cur; 65 } 66 67 private int removeOldest(){ 68 Node lastNode = tail.prev; 69 lastNode.prev.next = lastNode.next; 70 lastNode.next.prev = lastNode.prev; 71 return lastNode.key; 72 } 73 } 74 75 /** 76 * Your LRUCache object will be instantiated and called as such: 77 * LRUCache obj = new LRUCache(capacity); 78 * int param_1 = obj.get(key); 79 * obj.put(key,value); 80 */
另一种方法是用LinkedHashMap, 这种数据结构本身已经把HashMap按照添加顺序放好了。
可以参见这个网页:http://www.tutorialspoint.com/java/java_linkedhashmap_class.htm
所以实现起来很简洁,get时需要更新位置,更新位置是通过删掉旧的,复制一下加回去。
set时参照上面的三种情况即可。
AC Java:
1 import java.util.LinkedHashMap; 2 public class LRUCache { 3 LinkedHashMap<Integer, Integer> linkedHM; 4 int capacity; 5 public LRUCache(int capacity) { 6 linkedHM = new LinkedHashMap<Integer, Integer>(); 7 this.capacity = capacity; 8 } 9 10 public int get(int key) { 11 if(linkedHM.containsKey(key)){ 12 int val = linkedHM.get(key); 13 linkedHM.remove(key); 14 linkedHM.put(key,val); 15 return val; 16 } 17 return -1; 18 } 19 20 public void set(int key, int value) { 21 if(linkedHM.containsKey(key)){ 22 linkedHM.remove(key); 23 linkedHM.put(key,value); 24 }else if(linkedHM.size() < capacity){ 25 linkedHM.put(key,value); 26 }else{ 27 int oldKey = linkedHM.keySet().iterator().next(); 28 linkedHM.remove(oldKey); 29 linkedHM.put(key,value); 30 } 31 } 32 }