import java.util.*; class Node {//节点(数据单元) int key ; int val ; int count ;//节点访问的次数 Node(int key , int val) { this.key = key ; this.val = val ; } } class LFU {//缓存结构 //根据key查询Node HashMap<Integer , Node> dic ; /*根据访问次数count查询List(list里面存储所有访问次数为count的节点,并且约靠近链尾的节点约久未访问)*/ HashMap<Integer , LinkedList<Node>> tim ; int minTim ;//被访问最少的节点的 访问次数 int maxSize ;//LFU缓存的容量 int size ;//当前使用的容量 LFU(int capcity) { this.dic = new HashMap<>() ; this.tim = new HashMap<>() ; this.minTim = 0 ; this.maxSize = capcity ; this.size = 0 ; } //set(key,value) public void set(int key , int val) { if(dic.containsKey(key)) {//如果缓存中存在key Node find = dic.get(key) ; find.val = val ;//置换key所对应的value flush(find) ;//刷新一下访问记录,即让当前的访问次数加一,并且从原来的链表移动到新的链表 } else {//如果缓存中不存在key Node newNode = new Node(key , val) ;//新建节点 newNode.count = 1 ;//第一次访问 if(this.size == this.maxSize) {//如果缓存满了 removeByLFU() ;//置换 } else {//缓存未满,size加一 this.size ++ ; } dic.put(key , newNode) ;//存数据 if(tim.containsKey(1)) {//如果已经存在次数为1的链表 tim.get(1).addFirst(newNode) ;//直接添加,在链头哦 } else {//如果不存在次数为1的链表 LinkedList<Node> newList = new LinkedList<>() ;//新建一个链表 newList.add(newNode) ;//添加 this.minTim = 1 ;//刷新最小访问次数 tim.put(1 , newList) ;//将该链表以key为1,存入tim } } } //get(key) public int get(int key) { if(!dic.containsKey(key)) return -1 ;//不存在直接返回-1 Node find = dic.get(key) ;//得到对应的节点 flush(find) ;//刷新节点的访问记录 return find.val ; } //刷新节点的访问记录 public void flush(Node find) { LinkedList<Node> oldBelongsList = tim.get(find.count) ;//获取节点原来所在的链表 oldBelongsList.remove(find) ;//从原来的链表中移除 if(oldBelongsList.size() == 0) {//如果原来的链表已经没有数据了 if(find.count == this.minTim) {//并且 当前节点就是最少访问节点,那么要更新最少访问节点的访问次数 this.minTim ++ ; } tim.remove(find.count) ;//把空链表移除 } find.count ++ ;//当前节点的访问次数+1 if(tim.containsKey(find.count)) {//如果新的访问次数岁对应的链表已经存在 tim.get(find.count).addFirst(find) ;//则直接在新的链表中加入当前节点 } else {//如果新的访问次数岁对应的链表不存在 LinkedList<Node> newBelongsList = new LinkedList<>() ;//创建链表 newBelongsList.add(find) ;//添加节点 tim.put(find.count , newBelongsList) ;//将新的链表加入到tim中 } } //(淘汰访问次数最少的节点,次数一样则淘汰最久未访问的节点) public void removeByLFU() { LinkedList<Node> minTimList = tim.get(this.minTim) ;//获取最少访问次数所对应的链表 Node target = minTimList.get(minTimList.size()-1) ;//获取这个访问次数的"众多"节点中的最久未访问哪一个节点(即,链表尾部的那个节点) minTimList.remove(target) ;//删除那个节点 if(minTimList.size() == 0) {//如果这个链表已经空了,则将其从tim中移除掉 tim.remove(this.minTim) ; } dic.remove(target.key) ;//将节点从dic中移除 //注意:这个方法中并没有更新size和minTim,因为客户在调用本方法后,必定会再增加一个节点 //然后将minTim设置为1,(所以在本方法更新size和minTim多余,至少在这种实现的方式下是的,嘿嘿,才疏学浅,见谅!!) } } public class Solution { /** * lfu design * @param operators int整型二维数组 ops * @param k int整型 the k * @return int整型一维数组 */ public int[] LFU (int[][] operators, int k) { int getCount = (int)(Arrays.stream(operators).filter(a->a[0] == 2).count()) ; int res[] = new int[getCount] ; int index = 0 ; LFU lfu = new LFU(k) ; for(int i = 0 ; i < operators.length ; i ++) { if(operators[i].length == 2) { res[index ++] = lfu.get(operators[i][1]) ; } else { lfu.set(operators[i][1] , operators[i][2]) ; } } return res ; } }