Day71x.算法训练

文章介绍了LRU(最近最少使用)和LFU(最不经常使用)缓存的数据结构实现,包括使用双链表维护节点顺序,以及如何在有限容量下高效地插入、删除和查询数据。同时,还涉及到了设计一个随机级跳表的示例。
摘要由CSDN通过智能技术生成

146. LRU 缓存

class LRUCache {

    private DoublyLinkedList doublyLinkedList;
    
    private Map<Integer, Node> map;

    private int capacity;

    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    class DoublyLinkedList {

        private Node head;

        private Node tail;

        public DoublyLinkedList() {
            Node first = new Node();
            head = first;
            tail = first;
            head.next = tail;
            tail.pre = head;
        }

        public void remove(Node del) {
            Node pre = del.pre;
            Node next = del.next;
            pre.next = next;
            next.pre = pre;
        }

        public Node removeLast() {
            Node del = tail.pre;
            remove(del);
            return del;
        }

        public void addFirst(Node newNode) {
            Node next = head.next;

            head.next = newNode;
            newNode.pre = head;

            newNode.next = next;
            next.pre = newNode;
        }
    }

    class Node {
        private int key;
        private int value;
        private Node pre;
        private Node next;

        public int getKey() {
            return key;
        }

        public void setKey(int key) {
            this.key = key;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }

        public Node getPre() {
            return pre;
        }

        public void setPre(Node pre) {
            this.pre = pre;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }
    }

    public LRUCache(int capacity) {
        doublyLinkedList = new DoublyLinkedList();
        map = new HashMap<>();
        setCapacity(capacity);
    }

    public int get(int key) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            doublyLinkedList.remove(node);
            doublyLinkedList.addFirst(node);
            return node.value;
        } else {
            return -1;
        }
    }

    public void put(int key, int value) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            node.setValue(value);
            doublyLinkedList.remove(node);
            doublyLinkedList.addFirst(node);
        } else {
            Node newNode = new Node();
            newNode.setKey(key);
            newNode.setValue(value);
            doublyLinkedList.addFirst(newNode);
            map.put(key, newNode);
            if (map.size() > getCapacity()) {
                Node del = this.doublyLinkedList.removeLast();
                map.remove(del.key);
            }
        }
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

460. LFU 缓存

class LFUCache {

    private final Map<Integer, Node> kvMap;
    private final Map<Integer, DoublyLinkedList> freqMap;
    private int capacity;

    private int minFreq;

    public LFUCache(int capacity) {
        kvMap = new HashMap<>();
        freqMap = new HashMap<>();
        this.capacity = capacity;
    }

    public int get(int key) {
        if (!kvMap.containsKey(key)) {
            return -1;
        }
        Node node = kvMap.get(key);

        DoublyLinkedList doublyLinkedList = freqMap.get(node.freq);
        doublyLinkedList.remove(node);

        if (doublyLinkedList.isEmpty() && node.freq == minFreq) {
            minFreq++;
        }

        node.freq++;

        freqMap.computeIfAbsent(node.freq, integer -> new DoublyLinkedList()).addFirst(node);

        return node.value;
    }

    public void put(int key, int value) {
        if (kvMap.containsKey(key)) {
            Node node = kvMap.get(key);
            node.setValue(value);

            DoublyLinkedList doublyLinkedList = freqMap.get(node.freq);
            doublyLinkedList.remove(node);

            if (doublyLinkedList.isEmpty() && node.freq == minFreq) {
                minFreq++;
            }

            node.freq++;
            freqMap.computeIfAbsent(node.freq, integer -> new DoublyLinkedList()).addFirst(node);

        } else {
            if (kvMap.size() == capacity) {
                Node node = freqMap.get(minFreq).removeLast();
                kvMap.remove(node.key);
            }
            Node value1 = new Node();
            value1.setKey(key);
            value1.setValue(value);

            kvMap.put(key, value1);

            freqMap.computeIfAbsent(1, integer -> new DoublyLinkedList()).addFirst(value1);

            minFreq = 1;
        }
    }

    class DoublyLinkedList {

        private Node head;

        private Node tail;

        private int size;

        public DoublyLinkedList() {
            Node first = new Node();
            head = first;
            tail = first;
            head.next = tail;
            tail.pre = head;
        }

        public void remove(Node del) {
            Node pre = del.pre;
            Node next = del.next;
            pre.next = next;
            next.pre = pre;
            size--;
        }

        public Node removeLast() {
            Node del = tail.pre;
            remove(del);
            return del;
        }

        public void addFirst(Node newNode) {
            Node next = head.next;

            head.next = newNode;
            newNode.pre = head;

            newNode.next = next;
            next.pre = newNode;
            size++;
        }

        public boolean isEmpty() {
            return size == 0;
        }
    }

    class Node {
        private int key;
        private int value;
        private Node pre;
        private Node next;

        private int freq = 1;

        public int getKey() {
            return key;
        }

        public void setKey(int key) {
            this.key = key;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }

        public Node getPre() {
            return pre;
        }

        public void setPre(Node pre) {
            this.pre = pre;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        public int getFreq() {
            return freq;
        }

        public void setFreq(int freq) {
            this.freq = freq;
        }
    }
}

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

1206. 设计跳表

class Skiplist {

    private final int MAX = 10;

    private final Node head = new Node(-1);

    public Skiplist() {

    }

    public boolean search(int target) {
        Node[] nodes = find(target);
        Node node = nodes[0].next[0];
        return node != null && node.val == target;
    }

    public void add(int num) {
        Node[] path = find(num);

        Node node = new Node(num);

        int level = getRandomLevel(MAX);

        for (int i = 0; i < level; i++) {
            node.next[i] = path[i].next[i];
            path[i].next[i] = node;
        }
    }

    public boolean erase(int num) {
        Node[] path = find(num);

        Node node = path[0].next[0];

        if (node == null || node.val != num) {
            return false;
        }

        for (int i = 0; i < MAX; i++) {
            if (path[i].next[i] != node) {
                break;
            }
            path[i].next[i] = node.next[i];
        }
        return true;
    }

    public int getRandomLevel(int num) {
        Random random = new Random();
        int x = 1;
        while (x < num) {
            if (random.nextBoolean()) {
                return x;
            }
            x++;
        }
        return x;
    }

    private Node[] find(int num) {
        Node[] path = new Node[MAX];
        Node cur = head;
        for (int level = MAX - 1; level >= 0; level--) {
            while (cur.next[level] != null && cur.next[level].val < num) {
                cur = cur.next[level];
            }
            path[level] = cur;
        }
        return path;
    }

    class Node {

        private int val;

        private Node[] next = new Node[MAX];

        public Node(int value) {
            this.val = value;
        }

        public int getVal() {
            return val;
        }

        public void setVal(int val) {
            this.val = val;
        }

        public Node[] getNext() {
            return next;
        }

        public void setNext(Node[] next) {
            this.next = next;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EVE(伊娃)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值