• LRUCache示例 (LeetCode146)


    链接

    LeetCode146

    JAVA

    方法1

    • 采用HashMap存储键值对;
    • 采用LinkedHashSet存储键的使用情况,因为LinkedHashSet是按插入顺序来存储值的,当容量到顶时,直接删除第一个值即可。
    class LRUCache {
    
        private LinkedHashSet<Integer> lru;
    
        private HashMap<Integer, Integer> cache;
    
        private int capacity;
    
        public LRUCache(int capacity) {
            cache = new HashMap<>(capacity);
            lru = new LinkedHashSet<>();
            this.capacity = capacity;
        }
    
        public int get(int key) {
            if (!cache.containsKey(key)) {
                return -1;
            }
            lru.remove(key);
            lru.add(key);
            return cache.get(key);
        }
    
        public void put(int key, int value) {
            if (cache.containsKey(key)) {
                cache.put(key, value);
                lru.remove(key);
                lru.add(key);
            } else {
                cache.put(key, value);
                lru.add(key);
                if (cache.size() > capacity) {
                    int removeKey = -1;
                    for (Integer firstKey : lru) {
                        removeKey = firstKey;
                        break;
                    }
                    lru.remove(removeKey);
                    cache.remove(removeKey);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    方法2

    重写 LinkedHashMap 的 **removeEldestEntry()** 方法,使得当达到LRUCache缓存的容量上限时,删除掉最老的元素,也就是最近最少使用的元素。

    从LinkedHashMap的源码中看到,当在构造LinkedHashMap时设置了accessOrder 参数为true后,调用get()getOrDefault() 方法后,都会调用如下的 afterNodeAccess() 方法,将最近访问过的结点放发到最后。

    从LinkedHashMap的源码中看到,每次调用 put 方法后都会调用如下的 afterNodeInsertion() 方法,当 removeEldestEntry() 方法返回 true 时,就会删除 eldest 的结点。

    因此到我们重写 removeEldestEntry() 方法,使得容量大于LRUCache的capacity时删除掉最老的那个元素,也就实现了删除最近最少使用的目的,实现了LRUCache

    class LRUCache {
    
        private final int capacity;
    
        private final LinkedHashMap<Integer, Integer> map;
        
        public LRUCache(int capacity) {
            this.capacity = capacity;
    		/*
    		 Override the `removeEldestEntry` of LinkedHashmap.
    		 first param : capacity at the time the hash table is created
    		 second param: default load factor:  measure of how full the hash table is allowed
    		 https://stackoverflow.com/questions/10901752/what-is-the-significance-of-load-factor-in-hashmap
    		 third param: accessOrder – the ordering mode - true for access-order, false for insertion-order
    		*/
            map = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
                @Override
                protected boolean removeEldestEntry(Map.Entry eldest) {
                    return size() > capacity;
                }
            };
        }
    
        public int get(int key) {
            return map.getOrDefault(key, -1);
        }
    
        public void put(int key, int value) {
            map.put(key, value);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    虽然跟方法一的原理差不多,但是不得不说JAVA库函数的效率要高得多。


    C++

    class LRUCache {
    private:
        int cap;
        list<pair<int, int>> l;
        unordered_map<int, list<pair<int, int>>::iterator> m;
    public:
        LRUCache(int capacity) {
            this->cap = capacity;
        }
    
        int get(int key) {
            auto it = m.find(key);
            if (it == m.end()) return -1;
            l.splice(l.begin(), l, it->second);
            return it->second->second;
        }
    
        void put(int key, int value) {
            auto it = m.find(key);
            if (it != m.end()) l.erase(it->second);
            l.push_front(make_pair(key, value));
            m[key] = l.begin();
            if (m.size() > cap) {
                int k = l.rbegin()->first;
                l.pop_back();
                m.erase(k);
            }
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    OJ中C++偶尔会超时。


    参考文献

    [1] https://leetcode.com/problems/lru-cache/discuss/2425126/Java-solution-using-LinkedHashmap-(very-short-code).
    [2] https://leetcode.com/problems/lru-cache/discuss/2425119/Java-Solutionor-Using-LinkedHashMap-and-HashMap-without-using-removeEldestEntry()-of-LinkedHashMap.

  • 相关阅读:
    尚好房 07_前端房源展示
    ubuntu22.04 耳机没声音 [已解决]
    Vue基础(复习)
    【无标题】
    Docker更新Springboot的部署
    【英雄哥六月集训】第 24天: 线段树
    Android 中的 本地广播LocalBroadcastManager
    【深度思考】聊聊JDK动态代理原理
    vue3常见问题及解决方案(四)父组件切换行,然后子组件切换tab,子组件内的数据不刷新
    golang 多环境配置切换
  • 原文地址:https://blog.csdn.net/qq_27198345/article/details/126357534