leetcode460. LFU 缓存

题目

请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。

实现 LFUCache 类:

  • LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象
  • int get(int key) - 如果键存在于缓存中,则获取键的值,否则返回 -1。
  • void put(int key, int value) - 如果键已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量时,则应该在插入新项之前,使最不经常使用的项无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最久未使用 的键。

注意「项的使用次数」就是自插入该项以来对其调用 get 和 put 函数的次数之和。使用次数会在对应项被移除后置为 0 。

 

进阶:

你是否可以在 O(1) 时间复杂度内执行两项操作?
 

示例:

输入:
["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
输出:
[null, null, null, 1, null, -1, 3, null, -1, 3, 4]

解释:
LFUCache lFUCache = new LFUCache(2);
lFUCache.put(1, 1);
lFUCache.put(2, 2);
lFUCache.get(1);      // 返回 1
lFUCache.put(3, 3);   // 去除键 2
lFUCache.get(2);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
lFUCache.put(4, 4);   // 去除键 1
lFUCache.get(1);      // 返回 -1(未找到)
lFUCache.get(3);      // 返回 3
lFUCache.get(4);      // 返回 4


提示:

  • 0 <= capacity, key, value <= 104
  • 最多调用 105 次 get 和 put 方法

 

实现

package lfu;


import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

public class LfuCache {
    public static void main(String[] args) {
        LfuCache cache = new LfuCache (2);
        cache.put("a", "1");
        cache.put("b", "2");
        cache.put("c", "3");
        System.out.println(cache.toString());
        System.out.println(cache.get("a"));
        System.out.println(cache.get("b"));
        cache.put("d", "4");
        System.out.println(cache.toString());
    }

    private int capacity;
    private int minFreq = 0;
    private Map<String, Node> key2Node;
    private Map<Integer, LinkedList<Node>> freq2Nodes;

    public LfuCache(int capacity) {
        if (capacity <= 0) {
            throw new IllegalArgumentException("capacity can not le 0");
        }

        this.capacity = capacity;
        this.key2Node = new HashMap<>(capacity);
        this.freq2Nodes = new HashMap<>(capacity);
    }

    public String get(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key can not be null");
        }

        Node node = key2Node.get(key);
        if (null == node) {
            return null;
        }

        resetPutNode(node);
        return node.value;
    }

    public void put(String key, String value) {
        if (key == null || value == key) {
            throw new IllegalArgumentException("key/value can not be null");
        }

        if (key2Node.containsKey(key)) {
            Node node = key2Node.get(key);
            node.value = value;
            resetPutNode(node);
        } else {
            if (key2Node.size() == capacity) {
                Node node = freq2Nodes.get(minFreq).removeFirst();
                key2Node.remove(node.key);
            }

            minFreq = 1;
            putNode(new Node(key, value));
        }
    }

    /**
     * 1、先进行原来 key2Node 及 freq2Nodes 的删除,如果 等于 minFreq 情况,需要minFreq++
     * 2、重新将 node 添加到 key2Node 及 freq2Nodes
     */
    private void resetPutNode(Node node) {
        LinkedList<Node> list = freq2Nodes.get(node.freq);
        if (list.size() == 1 && node.freq == minFreq) {
            minFreq++;
        }

        list.remove(node);
        putNode(node);
    }

    /**
     * 进行node。freq添加,然后添加到key2Node 和 count2Node 里面
     */
    private void putNode(Node node) {
        node.freq++;
        key2Node.put(node.key, node);
        LinkedList<Node> list = freq2Nodes.getOrDefault(node.freq, new LinkedList<>());
        list.addLast(node);
        freq2Nodes.put(node.freq, list);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("capacity = ").append(capacity).append("\n");
        sb.append("key2Node = ").append(key2Node).append("\n");
        sb.append("freq2Nodes = ").append(freq2Nodes).append("\n");
        return sb.toString();
    }

    private static class Node {
        public Node(String key, String value) {
            this.key = key;
            this.value = value;
        }


        String key;
        String value;
        int freq;

        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder("(");
            sb.append("key:").append(key).append(",");
            sb.append("value:").append(value).append(",");
            sb.append("freq:").append(freq).append(")");
            return sb.toString();
        }
    }
}

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值