设计LRU缓存结构

设计LRU缓存结构

描述

设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能

  • set(key, value):将记录(key, value)插入该结构
  • get(key):返回key对应的value值

[要求]

  1. set和get方法的时间复杂度为O(1)
  2. 某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
  3. 当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。

思路:

我们想要达到插入和获取都是O(1)的时间复杂度的话,那么我们需要借助双向链表和Hash表。

  1. 我们插入数据的时候同时插入链表和hash表,和将该节点插入到链表头
  2. 获取值的时候从hash表获取,将该节点移动到链表头
  3. 当插入数据的时候发现链表长度已经达到预定容量,则删除末尾节点

代码:


import java.util.*;


public class Solution {
    static class LRUCache<K, V> {
        public class Entry {
            K key;
            V value;
            Entry prev;
            Entry next;

            public Entry() {
            }

            public Entry(K key, V value) {
                this.key = key;
                this.value = value;
            }
        }

        /**
         * 虚拟头节点
         */
        private Entry head;
        /**
         * 虚拟尾节点
         */
        private Entry tail;
        /**
         * 链表长度
         */
        private int size;
        /**
         * 默认容量
         */
        private static final int DEFAULT_CAP = 10;
        /**
         * 容量
         */
        private int cap;
        private HashMap<K, Entry> cache;

        public LRUCache(int cap) {
            this.size = 0;
            this.cap = cap;
            this.cache = new HashMap<>(this.cap);
            head = new Entry();
            tail = new Entry();
            //将虚拟尾连接到头节点上,就不用管他了,一切操作在这个之间操作
            head.next = tail;
        }

        public LRUCache() {
            this.size = 0;
            this.cap = DEFAULT_CAP;
            this.cache = new HashMap<>(cap);
            head = new Entry();
            tail = new Entry();
            head.next = tail;
        }

        public V get(K key) {
            Entry entry = cache.get(key);
            if (entry != null) {
                //如果存在,则移动到链表头
                moveToHead(entry);
                return entry.value;
            }
            return null;
        }

        public void set(K key, V value) {
            Entry entry = cache.get(key);
            if (entry != null) {
                //更新值
                entry.value = value;
                //移动到头
                moveToHead(entry);
                //添加到缓存
                cache.put(key, entry);
            } else {
                Entry newEntry = new Entry(key, value);
                cache.put(key, newEntry);
                //往头部添加
                addToHead(newEntry);
                size++;
                //边界问题
                if (size > cap) {
                    //删除尾链表
                    cache.remove(tail.prev.key);
                    removeTail(tail.prev);
                    size--;
                }
            }
        }

        private void removeTail(Entry entry) {
            //删除节点
            removeNode(entry);
        }

        private void moveToHead(Entry entry) {
            //删除节点
            removeNode(entry);
            //移动到头部
            addToHead(entry);
        }

        private void addToHead(Entry entry) {
            //将当前节点的下一个节点指向头节点的下一个节点
            entry.next = head.next;
            //将当前节点的prev 指向虚拟头节点
            entry.prev = head;
            //接下来处理head的下一个节点,将head的下一个节点的prev指针指向添加节点
            head.next.prev = entry;
            //更新值
            head.next = entry;
        }

        private void removeNode(Entry entry) {
            //断开
            entry.prev.next = entry.next;
            entry.next.prev = entry.prev;
        }
    }
}

测试:

public static void main(String[] args) {
        Solution solution = new Solution();
        int[][] arr = new int[6][];
        arr[0] = new int[]{1, 1, 1};
        arr[1] = new int[]{1, 2, 2};
        arr[2] = new int[]{1, 3, 2};
        arr[3] = new int[]{2, 1};
        arr[4] = new int[]{1, 4, 4};
        arr[5] = new int[]{2, 2};

        int[] lru = solution.LRU(arr, 3);
        System.out.println(Arrays.toString(lru));
    }

    /**
     * lru design
     *
     * @param operators int整型二维数组 the ops
     * @param k         int整型 the k
     * @return int整型一维数组
     */
    public int[] LRU(int[][] operators, int k) {
        // write code here

        int resultLength = 0;
        for (int[] operator : operators) {
            if (operator[0] == 2) {
                resultLength++;
            }
        }
        int[] results = new int[resultLength];
        int index = 0;

        LRUCache<Integer, Integer> cache = new LRUCache(k);
        for (int[] operator : operators) {
            switch (operator[0]) {
                case 1:
                    cache.set(operator[1], operator[2]);
                    break;
                case 2:
                    results[index++] = cache.get(operator[1]) == null ? -1 : cache.get(operator[1]);
            }
        }
        return results;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值