牛客题霸每日一题LRU缓存结构设计,关联LFU缓存结构设计

LRU: Map + 自定义双向链表
import java.util.*;


public class Solution {
    /**
     * lru design
     * @param operators int整型二维数组 the ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
    public int[] LRU (int[][] operators, int k) {
        // write code here
        LRU lru = new LRU(k);
        List<Integer> res = new ArrayList<>(operators.length);
        for(int[] oper: operators){
            int op = oper[0];
            if(oper[0] == 2){
               res.add(lru.get(oper[1]));
            }
            else{
               lru.set(oper[1], oper[2]);
            }
        }
        int[] result = new int[res.size()];
        for(int i = 0; i < res.size(); ++i){
            result[i] = res.get(i);
        }
        return result;
    }
    

    
    private class LRU{
        private class Node{
            int key, val;
            Node prev, next;
            public Node(int k, int v, Node p, Node n){
                key = k;
                val = v;
                prev = p;
                next = n;
            }
        }
        private int MAXSIZE;
        private Node head;
        private Node tail;
        private Map<Integer, Node> map;
        public LRU(int k){
            MAXSIZE = k;
            head = new Node(0, 0, null, null);
            tail = new Node(0, 0, head, null);
            head.next = tail;
            map = new HashMap<>();
        }
        public int get(Integer key){
            Node curr = map.getOrDefault(key, null);
            if(curr == null){return -1;}
            remove(curr);
            insert(curr);
            return curr.val;
        }
        
        public void set(Integer key, Integer val){
            Node curr = map.getOrDefault(key, null);
            Node newNode = new Node(key, val, null, null);
            map.put(key, newNode);
            insert(newNode);
            if(curr != null){
                remove(curr);
            }else{
                if(map.size() > MAXSIZE){
                    Node oldest = tail.prev;
                    map.remove(oldest.key);
                    remove(oldest);
                }
            }
        }
        
        private void remove(Node curr){
            curr.prev.next = curr.next;
            curr.next.prev = curr.prev;
        }
        private void insert(Node curr){
            curr.next = head.next;
            curr.next.prev = curr;
            curr.prev = head;
            head.next = curr;
        }
    }
}

LFU第一种实现: Map+单个双向链表
import java.util.*;


public class Solution {
    /**
     * lfu design
     * @param operators int整型二维数组 ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
    public int[] LFU (int[][] operators, int k) {
        // write code here
        if(operators == null || operators.length == 0){return new int[0];}
        List<Integer> res = new ArrayList<>(10);
        MyLFU lfu = new MyLFU(k);
        for(int[] oper : operators){
            if(oper.length == 3){
                lfu.set(oper[1], oper[2]);
            }else{
                res.add(lfu.get(oper[1]));
            }
        }
        int len = res.size();
        int[] arr = new int[len];
        for(int i = 0; i < len; ++i){
            arr[i] = res.get(i);
        }
        return arr;
    }
    
    private class MyLFU{
        
        private class Node{
            public int key;
            public int val;
            public int count;
            public Node next;
            public Node prev;
            public Node(int k, int v){
                this.key = k;
                this.val = v;
                this.count = 1;
            }
        }
        
        private Node head = new Node(0, 0);    // next指向删除概率最小的元素
        private Node tail = new Node(0, 0);    // prev指向删除该旅最大的元素
        private int size = 0;
        private int capacity;
        private Map<Integer, Node> nodes = new HashMap<>(16);
        
        public MyLFU(int k){
            this.head.next = tail;
            this.tail.prev = head;
            this.capacity = k;
        }
        
        public int get(int key){
            if(this.nodes.containsKey(key)){
                Node node = this.nodes.get(key);
                ++node.count;
                this.adjustToHead(node);
                return node.val;
            }
            return -1;
        }
        
        public void set(int key, int val){
            if(this.nodes.containsKey(key)){
                Node node = this.nodes.get(key);
                node.val = val;
                ++node.count;
                this.adjustToHead(node);
            }else{
                Node node = new Node(key, val);
                Node curr = this.head;
                while(curr.next != tail && curr.next.count > 1){
                    curr = curr.next;
                }
                node.next = curr.next;
                curr.next.prev = node;
                curr.next = node;
                node.prev = curr;
                this.nodes.put(key, node);
                if(++this.size > this.capacity){
                    this.remove();
                }
            }
        }
        
        private void adjustToHead(Node node){
            Node prev = node.prev;
            while(prev != head && node.count >= prev.count){
                prev.next = node.next;
                node.next.prev = prev;
                node.next = prev;
                node.prev = prev.prev;
                prev.prev.next = node;
                prev.prev = node;
                prev = node.prev;
            }
        }
        
        private void remove(){
            this.nodes.remove(this.tail.prev.key);
            this.tail.prev.prev.next = this.tail;
            this.tail.prev = this.tail.prev.prev;;
        }
    }
}

LFU第二种实现:Map1存key->Node,Map2存频数->双向链表,同一双向链表里的节点的频数相同。该方法时间复杂度略优于第一种实现。
import java.util.*;


public class Solution {
    /**
     * lfu design
     * @param operators int整型二维数组 ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
    public int[] LFU (int[][] operators, int k) {
        // write code here
        if(operators == null || operators.length == 0){return new int[0];}
        List<Integer> res = new ArrayList<>(10);
        MyLFU lfu = new MyLFU(k);
        for(int[] oper : operators){
            if(oper.length == 3){
                lfu.set(oper[1], oper[2]);
            }else{
                res.add(lfu.get(oper[1]));
            }
        }
        int len = res.size();
        int[] arr = new int[len];
        for(int i = 0; i < len; ++i){
            arr[i] = res.get(i);
        }
        return arr;
    }
    
    private class MyLFU{
        
        private class Node{
            public int key;
            public int val;
            public int count;
            public Node next;
            public Node prev;
            public Node(int k, int v){
                this.key = k;
                this.val = v;
                this.count = 0;
            }
        }
        
        private class MyLinkedList{
            private Map<Integer, Node> map = new HashMap<>(16);
            private Node head = new Node(0, 0);    // head.next为最后删除的元素
            private Node tail = new Node(0, 0);    // tail.prev为优先删除的元素
            private int size = 0;
            public MyLinkedList(){
                this.head.next = this.tail;
                this.tail.prev = this.head;
            }
            public int size(){return this.size;}
            public Node pop(){
                Node node = this.tail.prev;
                if(node == this.head){return null;}
                node.prev.next = this.tail;
                this.tail.prev = node.prev;
                map.remove(node.key);
                --size;
                return node;
            }
            public void add(Node node){
                node.next = this.head.next;
                node.next.prev = node;
                this.head.next = node;
                node.prev = this.head;
                map.put(node.key, node);
                ++size;
            }
            public void removByKey(int key){
                if(!this.map.containsKey(key)){return;}
                Node node = map.get(key);
                node.prev.next = node.next;
                node.next.prev = node.prev;
                map.remove(key);
                --size;
            }
        }
        
        private int size = 0;
        private int minCount = 1;
        private int capacity;
        private Map<Integer, Node> nodes = new HashMap<>(16);          // key->Node
        private Map<Integer, MyLinkedList> freqs = new HashMap<>(16);  // count->MyLinkedList
        
        public MyLFU(int k){
            this.capacity = k;
        }
        
        public int get(int key){
            if(this.nodes.containsKey(key)){
                Node node = this.nodes.get(key);
                this.move(node);
                return node.val;
            }
            return -1;
        }
        
        public void set(int key, int val){
            Node node;
            if(!this.nodes.containsKey(key)){
                node = new Node(key, val);
                this.nodes.put(key, node);
                ++this.size;
            }else{
                node = this.nodes.get(key);
                node.val = val;
            }
            this.move(node);
            if(this.size > this.capacity){
                MyLinkedList list = this.freqs.get(this.minCount);
                Node poped = list.pop();
                this.nodes.remove(poped.key);
                if(list != null || list.size() == 0){
                    this.minCount = 0;
                    do{
                        list = this.freqs.getOrDefault(++this.minCount, null);
                    }while(list == null || list.size() == 0);
                }
                --this.size;
            }
        }
        
        private void move(Node node){
            MyLinkedList list = this.freqs.getOrDefault(node.count, null);
            if(list != null){ list.removByKey(node.key); }
            int newCount = ++node.count;
            if(!this.freqs.containsKey(newCount)){
                list = new MyLinkedList();
                this.freqs.put(newCount, list);
            }else{
                list = this.freqs.get(newCount);
            }
            list.add(node);
        }
    }
}


#牛客题霸#
全部评论
给六娃点赞!
点赞 回复 分享
发布于 2020-12-01 20:19

相关推荐

点赞 评论 收藏
分享
评论
1
1
分享
正在热议
# 25届秋招总结 #
439972次浏览 4484人参与
# 春招别灰心,我们一人来一句鼓励 #
41352次浏览 523人参与
# 北方华创开奖 #
107226次浏览 598人参与
# 地方国企笔面经互助 #
7908次浏览 18人参与
# 虾皮求职进展汇总 #
113287次浏览 880人参与
# 实习,投递多份简历没人回复怎么办 #
2453683次浏览 34846人参与
# 阿里云管培生offer #
119608次浏览 2219人参与
# 实习必须要去大厂吗? #
55552次浏览 959人参与
# 同bg的你秋招战况如何? #
75178次浏览 548人参与
# 提前批简历挂麻了怎么办 #
149763次浏览 1976人参与
# 投递实习岗位前的准备 #
1195578次浏览 18546人参与
# 你投递的公司有几家约面了? #
33165次浏览 188人参与
# 双非本科求职如何逆袭 #
661770次浏览 7394人参与
# 机械人春招想让哪家公司来捞你? #
157585次浏览 2267人参与
# 如果公司给你放一天假,你会怎么度过? #
4714次浏览 53人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
11214次浏览 253人参与
# 发工资后,你做的第一件事是什么 #
12359次浏览 61人参与
# 工作中,努力重要还是选择重要? #
35521次浏览 384人参与
# 参加完秋招的机械人,还参加春招吗? #
20068次浏览 240人参与
# 实习想申请秋招offer,能不能argue薪资 #
39205次浏览 314人参与
# 我的上岸简历长这样 #
451863次浏览 8087人参与
# 非技术岗是怎么找实习的 #
155829次浏览 2120人参与
牛客网
牛客企业服务