1. 程式人生 > >【LeetCode】LRU Cache 解題報告

【LeetCode】LRU Cache 解題報告

題外話:才連續寫了幾篇部落格,部落格排名竟然就不再是“千里之外”了,已經進入2萬名之內了。再接再厲,加油!

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.

【題意】

設計並實現一個支援get和set操作的快取:

get(key) - 存在時返回其值,否則返回-1;

set(key) - 不存在時插入新值,存在時更新其值,注意當容量滿時,需刪除最長時間沒有訪問的key,將其刪除,並插入新的key。

==================== Map+List 實現法 ====================

【思路】

用map結構實現<key, value>的儲存與讀取。

用一個list來記錄key被訪問時間的久遠,最近被訪問的放在list的最後,list中的第一個key表示最長時間沒被訪問的。

【Java程式碼】

class LRUCache {
    HashMap<Integer, Integer> map;
    ArrayList<Integer> list;
    int capacity;
    
    public LRUCache(int capacity) {
        map = new HashMap<Integer, Integer>(capacity);
        list = new ArrayList<Integer>(capacity);
        this.capacity = capacity;
    }
    
    public int get(int key) {
        if (map.get(key) == null) return -1;
        list.remove(new Integer(key)); 
        list.add(key);
        return map.get(key);
    }
    
    public void set(int key, int value) {
    	if (map.get(key) != null) {//原來存在key
    		map.put(key, value);
    		list.remove(new Integer(key)); 
            list.add(key);
    	} else {//原來不存在key
    		if (map.size() < capacity) {//容量不滿
    			map.put(key, value);
    			list.add(key);
    		} else {//容量滿
    			int leastkey = list.remove(0);
                list.add(key);
                map.remove(leastkey);
                map.put(key, value);
    		}
    	}
    }
}

【注意點】

題目要求是Least Recently Used,不僅 set 時要更新list,get 時也要更新list。

set 時,需先判斷map中有無該值,若沒有再判斷map是否滿了;如果反過來,即先判斷map是否為滿,再判斷map中有無該值,這樣就錯了。

因為如果map滿時,其中有該值,直接更新就好,而先判斷map是否為滿的話,就會導致刪除最長時間沒有被訪問的值。

【常規解法】

通常用一個雙向連結串列來記錄最長時間沒被訪問的元素,因為雙向連結串列可以在O(1)的時間內實現將某個結點移動到表頭和刪除尾部結點。

上面程式碼中用list實現,其remove時實際上是遍歷整個list來尋找某個結點的。

LeetCode沒有對時間作要求,面試時肯定會被要求的。