• LeetCode 146. LRU CacheLRU缓存机制 (C++/Java)


    题目:

    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.

    The cache is initialized with a positive capacity.

    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

    分析:

    设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

    获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
    写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

    按照所给的例子看一下cache内部是如何变化的。

      front back result
    put(1, 1) (1, 1)    
    put(2, 2) (2, 2) (1, 1)  
    get(1) (1, 1) (2, 2) 1
    put(3, 3) (3, 3) (1, 1)  
    get(2) (3, 3) (1, 1) -1
    put(4, 4) (4, 4) (3, 3)  
    get(1) (4, 4) (3, 3) -1
    get(3) (3, 3) (4, 4) 3
    get(4) (4, 4) (3, 3) 4

    很清楚的就理解了LRU的机制,当get的key在cache中已经存在时,就将存储的内容放到最前面,get的key不存在时就返回-1。

    put的新的key-value时,如果达到了容量上限,就删除一个最近最少使用的,实际上也是队尾的元素,然后将新的key-value存储到最前面。

    因为我们每次要O(1)的复杂度,所以可以使用hashmap来get数据,而当容量达到上限时,要删除最近最少使用的,且要在最前面put进新的数据,要使用一个双向链表,来保证O(1)的时间复杂度。

    java中可以使用LinkeHashMap来实现LRU缓存。

    程序:

    C++

    class LRUCache {
    public:
        LRUCache(int capacity) {
            cap = capacity;
        }
        
        int get(int key) {
            auto it = map.find(key);
            if(it == map.end())
                return -1;
            l.splice(l.begin(), l, it->second);
            return it->second->second;
        }
        
        void put(int key, int value) {
            auto it = map.find(key);
            if(it != map.end()){
                l.erase(it->second);
            }
            l.push_front(make_pair(key, value));
            map[key] = l.begin();
            if (map.size() > cap) {
                int k = l.rbegin()->first;
                l.pop_back();
                map.erase(k);
            }
        }
    private:
        int cap;
        list<pair<int, int>> l;
        unordered_map<int, list<pair<int, int>>::iterator> map;
    };

    Java

    class LRUCache {
    
        public LRUCache(int capacity) {
            this.cap = capacity;
            this.map = new HashMap<>();
            this.dummyHead = new Node(0, 0);
            this.tail = new Node(0, 0);
    
            dummyHead.prev = null;
            dummyHead.next = tail;
            tail.prev = dummyHead;
            tail.next = null;
        }
    
        public int get(int key) {
            if(!map.containsKey(key))
                return -1;
            Node node = map.get(key);
            removeNode(node);
            addToHead(node);
            return node.val;
        }
    
        public void put(int key, int value) {
            if(map.containsKey(key)){
                Node node = map.get(key);
                removeNode(node);
                map.remove(key);
                size--;
            }
            Node node = new Node(key, value);
            map.put(key, node);
            if(size < cap){
                addToHead(node);
                size++;
            }else {
                map.remove(tail.prev.key);
                removeNode(tail.prev);
                addToHead(node);
            }
        }
    
        private void removeNode(Node node){
            node.prev.next = node.next;
            node.next.prev = node.prev;
        }
    
        private void addToHead(Node node){
            node.next = dummyHead.next;
            node.next.prev = node;
            dummyHead.next = node;
            node.prev = dummyHead;
        }
    
        class Node{
            int key;
            int val;
            Node prev;
            Node next;
            public Node(int key, int val){
                this.key = key;
                this.val = val;
            }
        }
        private int cap;
        private Map<Integer, Node> map;
        private Node dummyHead;
        private Node tail;
        private int size;
    }
    class LRUCache {
    
        public LRUCache(int capacity) {
            this.capacity = capacity;
            map = new LinkedHashMap<>();
        }
        
        public int get(int key) {
            if(map.containsKey(key)) {
                int value = map.get(key);
                map.remove(key);
                map.put(key, value);
                return value;
            }
            return -1;
        }
        
        public void put(int key, int value) {
            if(map.containsKey(key)) {
                map.remove(key);
            }
            map.put(key, value);
            if(map.size() > capacity) {
                map.remove(map.keySet().iterator().next());
            }
        }
        private int capacity;
        private LinkedHashMap<Integer, Integer> map;
    }
  • 相关阅读:
    POJ 3468 A Simple Problem with Integers(线段树区间求和)
    windows+Ubuntu双系统 windows引导修复
    CSDN博文大赛火爆开启
    TNS-12541,TNS-12560,TNS-00511,TNS-12542,TNS-12560,TNS-00512数据库启动监听报错
    MResource
    【LeetCode】【Python】Linked List Cycle
    中间件解析FDMEMTABLE.delta生成SQL的方法
    TDSTCPServerTransport 的Filters
    DATASNAP压缩过滤器的使用
    咏南CS插件开发框架也可BS方式部署
  • 原文地址:https://www.cnblogs.com/silentteller/p/12154455.html
Copyright © 2020-2023  润新知