LFU之Java的O(1)实现

最近字节面试碰到一个算法题LFU,LeetCode 460题,记录一下算法思路以及代码实现
本文是参考Leetcode @liweiwei1419 解答思路实现,原文连接
在这里插入图片描述
代码实现(Java):

package com.wzy;

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

public class LFUCache {

    private Map<Integer, ListNode> map;

    private int capacity;

    private Map<Integer, TLinkedList> countMap;
    // 全局最小频次
    private int min_frequency;

    public class ListNode {
        int key;
        int val;
        int frequency;
        ListNode pre;
        ListNode next;

        ListNode() {  }
        ListNode(int key, int val) {
            this.key = key;
            this.val = val;
            this.frequency = 1;
        }
    }

    public LFUCache(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<>(capacity);
        this.countMap = new HashMap<>();
        this.min_frequency = Integer.MAX_VALUE;
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        ListNode node = map.get(key);
        if (node == null) {
            return -1;
        }
        handle(node, false);
        return node.val;
    }


    /**
     * 关键函数,当put/set操作发生后调用此函数,分为新增结点以及对现有结点操作
     * 1、新增结点:直接接到对于频次的双向链表头部
     * 2、已存在结点:从老结点所在频次对应的双向链表中删除此结点后,再将其加入到频次+1对应的双向链表的头部
     * @param node 结点
     * @param isNew 是否是新增结点
     */
    private void handle(ListNode node, boolean isNew) {
        int frequency = node.frequency;
        //维护全局最小频次
        min_frequency = Math.min(frequency, min_frequency);
        if (countMap.containsKey(node.frequency)) {
            TLinkedList oldlist = countMap.get(node.frequency);
            if (!isNew) {
                node.frequency++;
                oldlist.removeNode(node);
                // 如果
                // 1、当前结点不为新增结点
                // 2、当前结点频次==全局最小频次
                // 3、且删除该结点后,对应频次双向链表为空,
                // 则全局最小频次+1
                if (frequency == min_frequency && oldlist.count == 0) {
                    min_frequency++;
                }
            }
        }
        if (!countMap.containsKey(node.frequency)) {
            countMap.put(node.frequency, new TLinkedList());
        }
        TLinkedList newList = countMap.get(node.frequency);
        newList.addNode2Head(node);
    }


    public void put(int key, int val) {
        if(capacity == 0) return;
        ListNode node;
        if (map.containsKey(key)) {
            node = map.get(key);
            node.val = val;
            handle(node, false);
        } else {
            node = new ListNode(key, val);
            //容量超出,则删除全局最小频次对应双向链表中的尾部结点
            if (map.size() >= capacity) {
                TLinkedList oldList = countMap.get(min_frequency);
                ListNode tail = oldList.removeTail();
                map.remove(tail.key);
            }
            map.put(key, node);
            handle(node, true);
        }

    }

    class TLinkedList {
        //含有多少个结点,不包含虚拟头尾结点
        int count;
        //虚拟头结点
        ListNode dummyHead;
        //虚拟尾结点
        ListNode dummyTail;

        TLinkedList() {
            this.count = 0;
            this.dummyHead = new ListNode();
            this.dummyTail = new ListNode();
            this.dummyHead.next = this.dummyTail;
            this.dummyTail.pre = this.dummyHead;
        }

        void addNode2Head(ListNode node) {
            node.next = dummyHead.next;
            dummyHead.next.pre = node;
            node.pre = dummyHead;
            dummyHead.next = node;
            this.count++;
        }

        ListNode removeNode(ListNode node) {
            ListNode pre = node.pre;
            ListNode next = node.next;
            pre.next = next;
            next.pre = pre;
            this.count--;
            return node;
        }


        ListNode removeTail() {
            ListNode node = this.dummyTail.pre;
            node.pre.next = this.dummyTail;
            this.dummyTail.pre = node.pre;
            node.pre = null;
            node.next = null;
            this.count--;
            return node;
        }

    }

    /**
     * ["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]]
     *
     * @param args
     */
    // public static void main(String[] args) {
    //     LFUCache cache = new LFUCache(2);
    //     cache.set(1, 1);
    //     cache.set(2, 2);
    //     System.out.println(cache.get(1));
    //     cache.set(3, 3);
    //     System.out.println(cache.get(2));
    //     System.out.println(cache.get(3));
    //     cache.set(4, 4);
    //     System.out.println(cache.get(1));
    //     System.out.println(cache.get(3));
    //     System.out.println(cache.get(4));
    // }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值