LeetCode OJ - LRU Cache

这题AC的前提是get()和set()操作都得是O(1),不过题中没有说明这点(所以我一开始Naive的用了两个数组分别表示Key 和Value,想都不用想每个操作定然会达到N)。后来是看了discuss后,决定采用HashMap+LinkedList,但是结果还是一直TLE,其实TLE是预料中的,因为LinkedList的底层虽然是双向链表,我们在remove其中一个元素时,需要先通过遍历链表才能找到这个元素,这个遍历就使得时间复杂度为O(n)。

最后在网上看到这样一个blog ,我觉得里头一个数据结构画的特别形象,如下:

有了这个提示,写自己的代码并不难,但是双向链表的操作特别需要细心和耐心,很容易出错。下面是我的Java代码,已AC。

  1 package leetcode;
  2 
  3 import java.util.HashMap;
  4 /**
  5  * 自己建一个双向链表
  6  * 表头表示最新使用过得、表尾表示latest least used
  7  * 采用LinkedList<E>没法在O(1)的时间内删除某个节点(我感觉是这样)
  8  * @author Echo
  9  *
 10  */
 11 class DNode
 12 {
 13     int key;
 14     int value;
 15     DNode next;
 16     DNode pre;
 17     public DNode()
 18     {
 19     }
 20     public DNode(int k, int v)
 21     {
 22         key = k;
 23         value = v;
 24     }
 25 }
 26 /**
 27  * 下面是LRU这个类
 28  * @author Echo
 29  *
 30  */
 31 public class LRUCache1 {
 32     //key和DNode是很明显的对应关系,并且hash表中的value之间又是双向链表
 33     HashMap<Integer,DNode> KV ; //这个数据结构可以参考 http://www.programcreek.com/2013/03/leetcode-lru-cache-java/
 34     DNode head ; //表示双向链表的表头
 35     DNode tail ; //表示双向链表的表尾
 36     int cap; //cache的容量
 37     int sz = 0; //cache的实际size
 38     public LRUCache1(int capacity)
 39     {
 40         cap = capacity;
 41         KV = new HashMap<Integer,DNode>(cap); 
 42     }
 43     /**
 44      *  Get the value (will always be positive) of the key if the key exists in the cache,
 45      *  otherwise return -1.
 46      * @param key
 47      * @return
 48      */
 49     public int get(int key)
 50     {
 51         if(KV.containsKey(key))
 52         {
 53             DNode u = KV.get(key);    
 54             remove(u);
 55             addHead(u);
 56             KV.put(key, u);
 57             return u.value;
 58         }
 59         return -1;
 60     }
 61     /**
 62      * Set or insert the value if the key is not already present. 
 63      * When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
 64      * @param key
 65      * @param value
 66      */
 67     public void set(int key, int value)
 68     {
 69         DNode u = new DNode(key,value);
 70         if(get(key) == -1)
 71         {    
 72             if(sz<cap)
 73             {
 74                 KV.put(key, u);
 75                 addHead(u);
 76                 sz++;
 77             }
 78             else{
 79                 int tailK = tail.key;
 80                 KV.remove(tailK);
 81                 if(tail == head)
 82                 {
 83                     tail = null;
 84                     head = null;
 85                     addHead(u);
 86                     KV.put(key, u);
 87                 }else{
 88                     DNode temp = tail.pre;
 89                     temp.next = null;
 90                     tail = temp;
 91                     addHead(u);
 92                     KV.put(key, u);
 93                 }
 94                 
 95             }
 96         }else
 97         
 98             KV.get(key).value = value;    
 99     }
100     private void addHead(DNode u) {
101         // TODO Auto-generated method stub
102         if(head == null)
103         {
104             head = u;
105             tail = u;
106         }else{
107             head.pre = u;
108             u.next = head;
109             head = u;
110             u.pre = null;
111         }
112         
113         //return head;
114     }
115     private DNode remove(DNode n)
116     {
117         DNode pre = n.pre;
118         DNode next = n.next;
119         if(pre == null && next == null)
120         {
121             head = null;
122             tail = null;
123             return null;
124         }
125         if(pre == null)
126         {
127             n.next.pre = null;
128             head = n.next;
129             return n.next;
130         }
131         if(next == null)
132         {
133             n.pre.next = null;
134             tail = n.pre;
135             return n.pre;
136         }
137         pre.next = n.next;
138         next.pre = pre;
139         return pre;
140     }
141     /**
142      * @param args
143      */
144     public static void main(String[] args) {
145         // TODO Auto-generated method stub
146         LRUCache1 lu = new LRUCache1(1);
147         lu.set(2, 1);
148         System.out.println(lu.get(2));
149         lu.set(3,2);
150         System.out.println(lu.get(2));
151         System.out.println(lu.get(3));
152     }
153 
154 }

 

posted @ 2014-04-22 23:25  echoht  阅读(280)  评论(0编辑  收藏  举报