zoukankan      html  css  js  c++  java
  • [LeetCode] 460. LFU Cache 最近最不常用页面置换缓存器

    Design and implement a data structure for Least Frequently Used (LFU) 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 reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.

    Follow up:
    Could you do both operations in O(1) time complexity?

    Example:

    LFUCache cache = new LFUCache( 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.get(3);       // returns 3.
    cache.put(4, 4);    // evicts key 1.
    cache.get(1);       // returns -1 (not found)
    cache.get(3);       // returns 3
    cache.get(4);       // returns 4

    双向链表(Doubly Linked List) + 哈希表(Hash Table)

     Java:

    public class LFUCache {
        Node head = null;
        final int capacity;
        Map<Integer, Integer> valueMap;
        Map<Integer, Node> nodeMap;
    
        public LFUCache (int capacity) {
            this.capacity = capacity;
            valueMap = new HashMap<>(this.capacity, 1f);
            nodeMap = new HashMap<>(this.capacity, 1f);
        }
    
        public int get(int key) {
            if (valueMap.containsKey(key)) increase(key, valueMap.get(key));
            return valueMap.getOrDefault(key, -1);
        }
    
        private void increase(int key, int value) {
            Node node = nodeMap.get(key);
            node.keys.remove(key);
            if (Objects.isNull(node.next)) node.next = new Node(node, null, 1 + node.count, key);
            else if (node.next.count == node.count + 1) node.next.keys.add(key);
            else node.next = node.next.prev = new Node(node, node.next, node.count + 1, key);
            nodeMap.put(key, node.next);
            valueMap.put(key, value);
            if (node.keys.isEmpty()) remove(node);
        }
    
        private void remove(Node node) {
            if (head == node) head = node.next;
            else node.prev.next = node.next;
            if (Objects.nonNull(node.next)) node.next.prev = node.prev;
        }
    
        public void set(int key, int value) {
            if (0 == this.capacity) return;
            if (valueMap.containsKey(key)) {
                increase(key, value);
            } else {
                if (valueMap.size() == this.capacity) remove();
                valueMap.put(key, value);
                add(key);
            }
        }
    
        private void add(int key) {
            if (Objects.isNull(head)) head = new Node(null, null, 1, key);
            else if (head.count == 1) head.keys.add(key);
            else head = head.prev = new Node(null, head, 1, key);
            nodeMap.put(key, head);
        }
    
        private void remove() {
            if (Objects.isNull(head)) return;
            int oldest = head.keys.iterator().next();
            head.keys.remove(oldest);
            if (head.keys.isEmpty()) remove(head);
            nodeMap.remove(oldest);
            valueMap.remove(oldest);
        }
    
        class Node {
            public Node prev, next;
            public final int count;
            public LinkedHashSet<Integer> keys = new LinkedHashSet<>();
    
            public Node(Node prev, Node next, int count, int key) {
                this.prev = prev;
                this.next = next;
                this.count = count;
                keys.add(key);
            }
        }
    } 

    Python:

    class KeyNode(object):
        def __init__(self, key, value, freq = 1):
            self.key = key
            self.value = value
            self.freq = freq
            self.prev = self.next = None
    
    class FreqNode(object):
        def __init__(self, freq, prev, next):
            self.freq = freq
            self.prev = prev
            self.next = next
            self.first = self.last = None
    
    class LFUCache(object):
    
        def __init__(self, capacity):
            """
            
            :type capacity: int
            """
            self.capacity = capacity
            self.keyDict = dict()
            self.freqDict = dict()
            self.head = None
    
        def get(self, key):
            """
            :type key: int
            :rtype: int
            """
            if key in self.keyDict:
                keyNode = self.keyDict[key]
                value = keyNode.value
                self.increase(key, value)
                return value
            return -1
    
        def set(self, key, value):
            """
            :type key: int
            :type value: int
            :rtype: void
            """
            if self.capacity == 0:
                return
            if key in self.keyDict:
                self.increase(key, value)
                return
            if len(self.keyDict) == self.capacity:
                self.removeKeyNode(self.head.last)
            self.insertKeyNode(key, value)
    
        def increase(self, key, value):
            """
            Increments the freq of an existing KeyNode<key, value> by 1.
            :type key: str
            :rtype: void
            """
            keyNode = self.keyDict[key]
            keyNode.value = value
            freqNode = self.freqDict[keyNode.freq]
            nextFreqNode = freqNode.next
            keyNode.freq += 1
            if nextFreqNode is None or nextFreqNode.freq > keyNode.freq:
                nextFreqNode = self.insertFreqNodeAfter(keyNode.freq, freqNode)
            self.unlinkKey(keyNode, freqNode)
            self.linkKey(keyNode, nextFreqNode)
    
        def insertKeyNode(self, key, value):
            """
            Inserts a new KeyNode<key, value> with freq 1.
            :type key: str
            :rtype: void
            """
            keyNode = self.keyDict[key] = KeyNode(key, value)
            freqNode = self.freqDict.get(1)
            if freqNode is None:
                freqNode = self.freqDict[1] = FreqNode(1, None, self.head)
                if self.head:
                    self.head.prev = freqNode
                self.head = freqNode
            self.linkKey(keyNode, freqNode)
    
        def delFreqNode(self, freqNode):
            """
            Delete freqNode.
            :rtype: void
            """
            prev, next = freqNode.prev, freqNode.next
            if prev: prev.next = next
            if next: next.prev = prev
            if self.head == freqNode: self.head = next
            del self.freqDict[freqNode.freq]
    
        def insertFreqNodeAfter(self, freq, node):
            """
            Insert a new FreqNode(freq) after node.
            :rtype: FreqNode
            """
            newNode = FreqNode(freq, node, node.next)
            self.freqDict[freq] = newNode
            if node.next: node.next.prev = newNode
            node.next = newNode
            return newNode
    
        def removeKeyNode(self, keyNode):
            """
            Remove keyNode
            :rtype: void
            """
            self.unlinkKey(keyNode, self.freqDict[keyNode.freq])
            del self.keyDict[keyNode.key]
    
        def unlinkKey(self, keyNode, freqNode):
            """
            Unlink keyNode from freqNode
            :rtype: void
            """
            next, prev = keyNode.next, keyNode.prev
            if prev: prev.next = next
            if next: next.prev = prev
            if freqNode.first == keyNode: freqNode.first = next
            if freqNode.last == keyNode: freqNode.last = prev
            if freqNode.first is None: self.delFreqNode(freqNode)
    
        def linkKey(self, keyNode, freqNode):
            """
            Link keyNode to freqNode
            :rtype: void
            """
            firstKeyNode = freqNode.first
            keyNode.prev = None
            keyNode.next = firstKeyNode
            if firstKeyNode: firstKeyNode.prev = keyNode
            freqNode.first = keyNode
            if freqNode.last is None: freqNode.last = keyNode
    
    # Your LFUCache object will be instantiated and called as such:
    # obj = LFUCache(capacity)
    # param_1 = obj.get(key)
    # obj.set(key,value)  

    Python:

    class CacheNode(object):
        def __init__(self, key, value, freq_node, pre, nxt):
            self.key = key
            self.value = value
            self.freq_node = freq_node
            self.pre = pre # previous CacheNode
            self.nxt = nxt # next CacheNode
    
        def free_myself(self):
            if self.freq_node.cache_head == self.freq_node.cache_tail:
                self.freq_node.cache_head = self.freq_node.cache_tail = None
            elif self.freq_node.cache_head == self:
                self.nxt.pre = None
                self.freq_node.cache_head = self.nxt
            elif self.freq_node.cache_tail == self:
                self.pre.nxt = None
                self.freq_node.cache_tail = self.pre
            else:
                self.pre.nxt = self.nxt
                self.nxt.pre = self.pre
    
            self.pre = None
            self.nxt = None
            self.freq_node = None
    
    class FreqNode(object):
        def __init__(self, freq, pre, nxt):
            self.freq = freq
            self.pre = pre # previous FreqNode
            self.nxt = nxt # next FreqNode
            self.cache_head = None # CacheNode head under this FreqNode
            self.cache_tail = None # CacheNode tail under this FreqNode
    
        def count_caches(self):
            if self.cache_head is None and self.cache_tail is None:
                return 0
            elif self.cache_head == self.cache_tail:
                return 1
            else:
                return '2+'
    
        def remove(self):
            if self.pre is not None:
                self.pre.nxt = self.nxt
            if self.nxt is not None:
                self.nxt.pre = self.pre
    
            pre = self.pre
            nxt = self.nxt
            self.pre = self.nxt = self.cache_head = self.cache_tail = None
    
            return (pre, nxt)
    
        def pop_head_cache(self):
            if self.cache_head is None and self.cache_tail is None:
                return None
            elif self.cache_head == self.cache_tail:
                cache_head = self.cache_head
                self.cache_head = self.cache_tail = None
                return cache_head
            else:
                cache_head = self.cache_head
                self.cache_head.nxt.pre = None
                self.cache_head = self.cache_head.nxt
                return cache_head
    
        def append_cache_to_tail(self, cache_node):
            cache_node.freq_node = self
    
            if self.cache_head is None and self.cache_tail is None:
                self.cache_head = self.cache_tail = cache_node
            else:
                cache_node.pre = self.cache_tail
                cache_node.nxt = None
                self.cache_tail.nxt = cache_node
                self.cache_tail = cache_node
    
        def insert_after_me(self, freq_node):
            freq_node.pre = self
            freq_node.nxt = self.nxt
    
            if self.nxt is not None:
                self.nxt.pre = freq_node
            
            self.nxt = freq_node
    
        def insert_before_me(self, freq_node):
            if self.pre is not None:
                self.pre.nxt = freq_node
            
            freq_node.pre = self.pre
            freq_node.nxt = self
            self.pre = freq_node
            
    class LFUCache(object):
    
        def __init__(self, capacity):
            self.cache = {} # {key: cache_node}
            self.capacity = capacity
            self.freq_link_head = None
        
        def get(self, key):
            if key in self.cache:
                cache_node = self.cache[key]
                freq_node = cache_node.freq_node
                value = cache_node.value
    
                self.move_forward(cache_node, freq_node)
    
                return value
            else:
                return -1
    
        def set(self, key, value):
            if self.capacity <= 0:
                return -1
            
            if key not in self.cache:
                if len(self.cache) >= self.capacity:
                    self.dump_cache()
    
                self.create_cache(key, value)
            else:
                cache_node = self.cache[key]
                freq_node = cache_node.freq_node
                cache_node.value = value
    
                self.move_forward(cache_node, freq_node)
    
        def move_forward(self, cache_node, freq_node):
            if freq_node.nxt is None or freq_node.nxt.freq != freq_node.freq + 1:
                target_freq_node = FreqNode(freq_node.freq + 1, None, None)
                target_empty = True
            else:
                target_freq_node = freq_node.nxt
                target_empty = False
            
            cache_node.free_myself()
            target_freq_node.append_cache_to_tail(cache_node)
    
            if target_empty:
                freq_node.insert_after_me(target_freq_node)
    
    
            if freq_node.count_caches() == 0:
                if self.freq_link_head == freq_node:
                    self.freq_link_head = target_freq_node
    
                freq_node.remove()
    
        def dump_cache(self):
            head_freq_node = self.freq_link_head
            self.cache.pop(head_freq_node.cache_head.key)
            head_freq_node.pop_head_cache()
    
            if head_freq_node.count_caches() == 0:
                self.freq_link_head = head_freq_node.nxt
                head_freq_node.remove()
    
        def create_cache(self, key, value):
            cache_node = CacheNode(key, value, None, None, None)
            self.cache[key] = cache_node
            
            if self.freq_link_head is None or self.freq_link_head.freq != 0:
                new_freq_node = FreqNode(0, None, None)
                new_freq_node.append_cache_to_tail(cache_node)
    
                if self.freq_link_head is not None:
                    self.freq_link_head.insert_before_me(new_freq_node)
                
                self.freq_link_head = new_freq_node
            else:
                self.freq_link_head.append_cache_to_tail(cache_node)
    

    C++:

    class LFUCache {
    public:
        LFUCache(int capacity) {
            cap = capacity;
        }
        
        int get(int key) {
            if (m.count(key) == 0) return -1;
            freq[m[key].second].erase(iter[key]);
            ++m[key].second;
            freq[m[key].second].push_back(key);
            iter[key] = --freq[m[key].second].end();
            if (freq[minFreq].size() == 0) ++minFreq;
            return m[key].first;
        }
        
        void put(int key, int value) {
            if (cap <= 0) return;
            if (get(key) != -1) {
                m[key].first = value;
                return;
            }
            if (m.size() >= cap) {
                m.erase(freq[minFreq].front());
                iter.erase(freq[minFreq].front());
                freq[minFreq].pop_front();
            }
            m[key] = {value, 1};
            freq[1].push_back(key);
            iter[key] = --freq[1].end();
            minFreq = 1;
        }
    
    private:
        int cap, minFreq;
        unordered_map<int, pair<int, int>> m;
        unordered_map<int, list<int>> freq;
        unordered_map<int, list<int>::iterator> iter;
    };
    

      

    [LeetCode] 146. LRU Cache 近期最少使用缓存

      

    All LeetCode Questions List 题目汇总

  • 相关阅读:
    android自定义通知栏遇到的问题
    写博客号的初衷
    模型转换遇关键字
    界面传值的四种方式
    button循环添加事件
    解析数据的步骤
    数组排序 (数组是有序容器,因此集合中只有数组才能排序。)
    集合遍历
    自定义view和自定义cell
    cell自适应高度
  • 原文地址:https://www.cnblogs.com/lightwindy/p/9557874.html
Copyright © 2011-2022 走看看