笔试常考超详细设计LRU缓存结构,一看就会!!!

设计LRU缓存结构

设计LRU缓存结构
示例1

输入: [[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
返回值: [1,-1]
说明:
第一次操作后:最常使用的记录为(“1”, 1) 第二次操作后:最常使用的记录为(“2”, 2),(“1”, 1)变为最不常用的
第三次操作后:最常使用的记录为(“3”, 2),(“1”, 1)还是最不常用的
第四次操作后:最常用的记录为(“1”, 1),(“2”,2)变为最不常用的
第五次操作后:大小超过了3,所以移除此时最不常使用的记录(“2”, 2),加入记录(“4”, 4),并且为最常使用的记录,然后(“3”, 2)变为最不常使用的记录

LUR

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

解题思路

数据结构:map+双向链表
HashMap<key,Node>
题目要求set、get操作都为O(1),对于get操作,我们自然想到用map可以解决。set操作,需要考虑题目的LRU特性,则我们需要有一个优先级的属性,自然想到了队列、链表这种结构,用位置来表达优先级。但是这种单向线性结构,remove()的操作需要先查找位置,复杂度为O(n),所以需要使用双向链表。
而get(key)操作:在map中找是否有此节点,如果有则返回节点value,并将此节点移动到最前,没有就返回-1
而put(node)操作:在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
            //初始化LUR
            LURcache lurcache=new LURcache(k);
            List<Integer> list = new ArrayList<>();
            for(int i=0;i<operators.length;i++){
                if(operators[i][0]==1){
                    lurcache.put(operators[i][1],operators[i][2]);
                }else{
                    list.add(lurcache.get(operators[i][1]));
                }
            }
            int[] res =new int[list.size()];
            for(int i=0;i<list.size();i++){
                res[i]=list.get(i);
            }
            return res;
        }
    }
    class LURcache{
        

        //定义双向链表
        class Node{
            int key,value;
            Node pre,next;
            public Node(int key,int value){
                this.key=key;
                this.value=value;
            }
        }
        
        //HashMap记录节点key,value
        Map<Integer,Node> map = new HashMap<>();
        //记录链表长度
        int size=0;
        //定义双向链表的头尾节点
        Node head = new Node(-1,-1);
        Node tail = new Node(-1,-1);
        //容量
        int cap;
        //从链表得到
        public int get(int key){
            Node node=map.get(key);
            //看在链表中即map中是否有此节点,如果有就将此节点放到最前,如果没就返回-1
            if(node==null){
                return -1;
            }
            move(node);
            return node.value;
        }
        public void put(int key,int value){
            Node node = map.get(key);
            if(node==null){
                //当链表中不存在即map中不存在这个节点时构建新节点
                Node cur = new Node(key,value);
                //如果链表的长度大于容量时删除最后一个,在把当前节点放到前面
                //反之就直接把节点放到最前
                if(size<cap){
                    insertFirst(cur);
                }else{
                    delete(tail.pre);
                    insertFirst(cur);
                }
            }else{
                //当有这个节点时,把这个节点更新这个节点并移动到最前面即删除最后加到最前
                node.value=value;
                move(node);
            }
        }
        //移动
        private void move(Node node){
            delete(node);
            insertFirst(node);
        }
        //删除
        private void delete(Node node){
            map.remove(node.key);
            node.pre.next=node.next;
            node.next.pre=node.pre;
            size--;
        }
        //增加
        private void insertFirst(Node node){
            map.put(node.key,node);
            node.next=head.next;
            head.next.pre=node;
            head.next=node;
            node.pre=head;
            size++;
        }
        public LURcache(int cap) {
            this.cap=cap;
            head.next=tail;
            tail.pre=head;
            tail.next=null;
        }
    }


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值