LeetCode 460. LFU Cache

29 篇文章 0 订阅
4 篇文章 0 订阅

原题网址:https://leetcode.com/problems/lfu-cache/

Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: getand 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

方法:和LRU Cache类似,但是用两层的链表,上层以频率为节点值,下层以键值对为节点值。

public class LFUCache {
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("(map: ");
        sb.append(map);
        sb.append(", nodes: ");
        FreqNode node = freqHead;
        while (node != null) {
            sb.append(node);
            node = node.next;
        }
        sb.append(")");
        return sb.toString();
    }
    private FreqNode freqHead = new FreqNode(0);
    private FreqNode freqTail = new FreqNode(0);
    {
        freqHead.next = freqTail;
        freqTail.prev = freqHead;
    }

    private int capacity;
    private Map<Integer, ValNode> map = new HashMap<>();

    public LFUCache(int capacity) {
        this.capacity = capacity;
    }

    private ValNode getValNode(int key) {
        ValNode valNode = map.get(new Integer(key));
        if (valNode == null) return null;
        FreqNode currFreq = valNode.freqNode;
        valNode.remove();
        if (currFreq.freq + 1 == currFreq.next.freq) {
            FreqNode nextFreq = currFreq.next;
            valNode.insertBefore(nextFreq.tail);
            valNode.freqNode = nextFreq;
        } else {
            FreqNode nextFreq = new FreqNode(currFreq.freq + 1);
            nextFreq.insertBefore(currFreq.next);
            valNode.insertBefore(nextFreq.tail);
            valNode.freqNode = nextFreq;
        }
        if (currFreq.head.next == currFreq.tail) currFreq.remove();
        return valNode;
    }
    public int get(int key) {
        if (capacity <= 0) return -1;
        ValNode valNode = getValNode(key);
        return valNode == null ? -1 : valNode.val;
    }

    public void put(int key, int value) {
        if (capacity <= 0) return;
        ValNode valNode = getValNode(key);
        if (valNode != null) {
            valNode.val = value;
            return;
        }

        if (map.keySet().size() == capacity) {
            map.remove(new Integer(freqHead.next.head.next.key));
            freqHead.next.head.next.remove();
            if (freqHead.next.head.next == freqHead.next.tail) {
                freqHead.next.remove();
            }
        }

        FreqNode freqNode = null;
        if (freqHead.next.freq == 1) {
            freqNode = freqHead.next;
        } else {
            freqNode = new FreqNode(1);
            freqNode.insertBefore(freqHead.next);
        }
        valNode = new ValNode(key, value, freqNode);
        valNode.insertBefore(freqNode.tail);
        map.put(new Integer(key), valNode);
    }

//    public static void main(String[] args) {
//        LFUCache cache = new LFUCache(2);
//        cache.put(0, 0);
//        cache.get(0);
//        cache.put(1, 100);
//        System.out.println(cache);
//        cache.put(2, 200);
//        System.out.println(cache);
//        cache.get(1);
//        System.out.println(cache);
//        cache.put(3, 300);
//        System.out.println(cache);
//        cache.get(2);
//        System.out.println(cache);
//        cache.get(3);
//        System.out.println(cache);
//        System.out.println(cache.get(1));
//        cache.put(1,100);
//        System.out.println(cache.get(1));
//        cache.put(2,200);
//        System.out.println(cache.get(1));
//    }
}

/**
 * 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);
 */

class FreqNode {
    FreqNode prev, next;
    void insertBefore(FreqNode node) {
        this.prev = node.prev;
        node.prev.next = this;
        this.next = node;
        node.prev = this;
    }
    void remove() {
        this.next.prev = this.prev;
        this.prev.next = this.next;
        this.prev = null;
        this.next = null;
    }

    int freq;
    ValNode head = new ValNode(0, 0, this);
    ValNode tail = new ValNode(0, 0, this);
    {
        head.next = tail;
        tail.prev = head;
    }
    FreqNode(int freq) {
        this.freq = freq;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("(freq: " + freq);
        ValNode node = this.head;
        while (node != null) {
            if (sb.length() > 0) sb.append(", ");
            sb.append(node);
            node = node.next;
        }
        sb.append(")");
        return sb.toString();
    }
}
class ValNode {
    ValNode prev, next;
    void insertBefore(ValNode node) {
        this.prev = node.prev;
        node.prev.next = this;
        this.next = node;
        node.prev = this;
    }
    void remove() {
        this.next.prev = this.prev;
        this.prev.next = this.next;
        this.prev = null;
        this.next = null;
    }

    int key;
    int val;
    FreqNode freqNode;
    ValNode(int key, int val, FreqNode freqNode) {
        this.key = key;
        this.val = val;
        this.freqNode = freqNode;
    }

    @Override
    public String toString() {
        return "(key: " + key + ", val: " + val + ", freq: " + freqNode.freq + ")";
    }

}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值