LRU & LFU Cache

LRU Cache

題目連接:https://leetcode.com/problems...node

這個題要求O(1)的複雜度。首先要作到get(key)是O(1),能想到的數據結構只有兩三種,一個是HashMap<key, value>,一個是List<value>,key是index,還有一個Array[value], key是index。array不太可能,由於長度要initial並且不可變,題目也沒說長度固定。list也不行,由於有put操做,list的insert操做是O(N)的。hashmap能夠作到get和put都是O(1)。由於還有put函數,要能夠remove least recently used cache,因此還須要一個數據結構來記錄順序,天然想到list。set以及delete操做在LinkedList裏面都是O(1),就是要找到已存在的key這個操做在list是O(N),由於即要刪除least recently的,也要加most recently的,因此是個double linked list。能夠把map裏面的value信息改爲key在list裏面該key對應的list node,而後在list裏面存value信息。這其實也就是LinkedHashMap能夠作的。web

public class LRUCache {
    class ListNode {
        ListNode prev;
        ListNode next;
        int val = 0;
        int key = 0;
        ListNode() {}
        ListNode(int key, int val) {
            this.key = key;
            this.val = val;
        }
    }
    // new node(most recently) add to the tail part
    public void append(ListNode node) {
        node.prev = tail.prev;
        tail.prev.next = node;
        node.next = tail;
        tail.prev = node;
    }
    
    // least recently node need to be remove from head
    public void remove() {
        remove(head.next);
    }

    // remove the certain node
    public void remove(ListNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    
    ListNode head, tail;
    Map<Integer, ListNode> map;
    int remain;
    public LRUCache(int capacity) {
        remain = capacity;
        // map for get
        map = new HashMap();
        // list for put 
        head = new ListNode();
        tail = new ListNode();
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        if(map.containsKey(key)) {
            // remove the key node to the tail
            int value = map.get(key).val;
            put(key, value);
            return value;
        }
        else return -1;
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)) {
            ListNode node = map.get(key);
            node.val = value;
            remove(node);
            append(node);
        }
        else {
            // not contain, check if count > capacity
            // remove the least recent node in list & map
            if(remain == 0) {
                map.remove(head.next.key);
                remove();
                remain++;
            }
            ListNode node = new ListNode(key, value);
            append(node);
            map.put(key, node);
            remain--;
        }
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

LFU Cache

題目連接:https://leetcode.com/problems...數據結構

上一題是隻考慮出現的時間,這題加了frequency。那麼再加一個map存freq應該是可行的。如今node除了要保存順序還得保存freq,感受上像是個二維的,先按freq排序再考慮出現順序。每次得保存下這個freq出現最先的值,再出現的時候,要從這freq裏刪了,移到下一個freq的tail上。想了下感受仍是不太好作,看了網上的答案。
參考這個博客:
http://bookshadow.com/weblog/...app

first -> point to the freqNode with freq = 1
Map<key, freqNode> freqMap
relation between freqNode:
first(freq 0) <-> freq 1 <-> freq 2 <-> ......
Map<key, keyNode> keyMap函數

get(key):this

  • case 1: return -1code

  • case 2: exist =>blog

    • find keyNode and remove from freqNode, if cur freqNode has no element, remove freqNode排序

    • find freqNode through freqMap,ci

    • find next freqNode(freq + 1) through freqNode,

    • add keyNode to the tail of next freqNode

put(key, value)

  • case 1: not exist in keyMap => add to the tail of freqNode with freq = 1

  • case 2: exist =>

    • find keyNode, set value and remove from freqNode, if cur freqNode has no element, remove freqNode

    • find freqNode through freqMap,

    • find next freqNode(freq + 1) through freqNode,

    • add keyNode to the tail of next freqNode

其中,keyNode和keyMap和上一題同樣都是能夠用LinkedHashMap來實現的。那麼這裏能夠稍微改一下,把keyMap裏面直接放<key, value>而後用一個LinkedHashSet來存全部有相同freq的keyNode,只須要存key便可。

public class LFUCache {
    class freqNode {
        int freq = 0;
        freqNode prev, next;
        // store keys
        LinkedHashSet<Integer> keyNodes = new LinkedHashSet();
        freqNode() {}
        freqNode(int freq) { this.freq = freq; }
        
        public int delete() {
            // if(keyNodes.isEmpty()) return;
            int key = keyNodes.iterator().next();
            keyNodes.remove(key);
            return key;
        }
        public void delete(int key) {
            // if(!keyNodes.contains(key)) return;
            keyNodes.remove(key);
        }
        public void append(int key) {
            keyNodes.add(key);
        }
    }
    
    int remain;
    // key, freqNode pair
    Map<Integer, freqNode> freqMap;
    // key, value pair
    Map<Integer, Integer> keyMap;
    freqNode first;
    freqNode last;
    public LFUCache(int capacity) {
        this.remain = capacity;
        freqMap = new HashMap();
        keyMap = new HashMap();
        first = new freqNode();
        last = new freqNode();
        first.next = last;
        last.next = first;
    }
    
    public int get(int key) {
        if(!keyMap.containsKey(key)) return -1;
        else {
            updateFreq(key);
            return keyMap.get(key);
        }
    }
    
    public void put(int key, int value) {
        if(!keyMap.containsKey(key)) {
            if(remain == 0) {
                if(first.next.freq == 0) return;
                // remove the least frequent
                int del = first.next.delete();
                keyMap.remove(del);
                freqMap.remove(del);
                remain++;
            }
            // update map and add node
            keyMap.put(key, value);
            update(first, key);
            remain--;
        }
        else {
            updateFreq(key);
            keyMap.put(key, value);
        }
    }
    
    
    
    private void updateFreq(int key) {
        freqNode node = freqMap.get(key);
        update(node, key);
        
        // remove current node if has no keyNodes
        node.delete(key);
        if(node.keyNodes.size() == 0) {
            removeNode(node);
        }
    }
    
    private void update(freqNode node, int key) {
        // append to the next freq
        addAfterNode(node);
        node.next.append(key);
        // update freqMap key with next freqNode
        freqMap.put(key, node.next);
    }
    
    private void addAfterNode(freqNode node) {
        if(node.next.freq != node.freq + 1) {
            freqNode newNode = new freqNode(node.freq + 1);
            freqNode temp = node.next;
            node.next = newNode;
            newNode.prev = node;
            temp.prev = newNode;
            newNode.next = temp;
            node = null;
        }
    }
    
    private void removeNode(freqNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    
}

/**
 * Your LFUCache object will be instantiated and called as such:
 * LFUCache obj = new LFUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */
相關文章
相關標籤/搜索