LRU Cache 三步优化方案

LRU Cache

首先说明这是携程2019年后端的笔试题

https://www.nowcoder.com/question/next?pid=16620108&qid=365880&tid=35966796

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 64M,其他语言128M

复制代码

  ``设计一个数据结构,实现LRU Cache的功能(Least Recently Used – 最近最少使用缓存)。它支持如下``2``个操作: get 和 put。` `int` `get(``int` `key) – 如果key已存在,则返回key对应的值value(始终大于``0``);如果key不存在,则返回-``1``。``void` `put(``int` `key, ``int` `value) – 如果key不存在,将value插入;如果key已存在,则使用value替换原先已经存在的值。如果容量达到了限制,LRU Cache需要在插入新元素之前,将最近最少使用的元素删除。` `请特别注意“使用”的定义:新插入或获取key视为被使用一次;而将已经存在的值替换更新,不算被使用。` `限制:请在O(``1``)的时间复杂度内完成上述``2``个操作。
输入描述:
第一行读入一个整数n,表示LRU Cache的容量限制。 从第二行开始一直到文件末尾,每1行代表1个操作。如果每行的第1个字符是p,则该字符后面会跟随2个整数,表示put操作的key和value。如果每行的第1个字符是g,则该字符后面会跟随1个整数,表示get操作的key。
输出描述:
按照输入中get操作出现的顺序,按行输出get操作的返回结果。
输入例子1:
2
p 1 1
p 2 2
g 1
p 2 102
p 3 3
g 1
g 2
g 3
输出例子1:
1
1
-1
3
例子说明1:
2        //Cache容量为2
p 1 1    //put(1, 1)
p 2 2    //put(2, 2)
g 1      //get(1), 返回1
p 2 102  //put(2, 102),更新已存在的key,不算被使用
p 3 3    //put(3, 3),容量超过限制,将最近最少使用的key=2清除
g 1      //get(1), 返回1
g 2      //get(2), 返回-1
g 3      //get(3), 返回3

第一版 —— 链表 ( get、put操作时间复杂度不为O(1))


import java.util.Scanner;

/**
 * @author gyh
 * @csdn https://blog.csdn.net/qq_40788718
 * @date 2020/8/14 21:31
 */

public class LRUTest {
	/** 双向链表 */
    static class Node{
        private int key ;
        private int value ;
        private Node pred ;
        private Node next ;

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

    static class LRU{
        /** 头节点 */
        private Node head ;
        /** 尾节点 */
        private Node tail ;
        /** 链表的固定容量 */
        private int capacity ;
        /** 链表实际长度 */
        private int size ;

        public LRU(int capacity){
            this.capacity = capacity ;
            this.size = 0 ;
            this.head = new Node(-1 , -1) ;
        }

        public int get(int key){
            Node node = search(key) ;
            //跳出来可能为空 或者找到key了
            if (node != null){
                delete(node);
                insert(node);
                return node.value ;
            }
            return -1 ;
        }

        public void put(int key , int value){
            Node node = search(key) ;
            if (node != null){
                node.value = value ;
                return ;
            }
            node = new Node(key , value) ;
          	//头插入
            insert(node) ;
            if (size > capacity){
                //尾删除
                delete(tail);
            }
        }

        private Node search(int key) {
            Node pre = head.next ;
            while(pre != null && pre.key != key){
                pre = pre.next ;
            }
            return pre ;
        }

        private void insert(Node node){
            Node second = head.next ;
            head.next = node ;
            node.pred = head ;
            node.next = second ;
            if (second != null){
                second.pred = node ;
            }else {
                tail = node ;
            }
            this.size ++ ;
        }

        private void delete(Node node){
            if (node == null){
                return ;
            }
            Node pred = node.pred ;
            Node next = node.next ;
            pred.next = next ;
            if (next != null){
                //node不是队尾
                next.pred = pred ;
            }else{
                this.tail = pred ;
            }
            node.pred = null ;
            node.next = null ;
            this.size -- ;
        }

        public void print(){
            System.out.println("====================");
            Node pre = head.next ;
            while(pre != null){
                System.out.println(pre.key + " " +pre.value);
                pre = pre.next ;
            }
            System.out.println("====================");
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        LRU lru = new LRU(input.nextInt()) ;
        while(input.hasNext()){
            String choose = input.next() ;
            if ("p".equals(choose)){
                lru.put(input.nextInt() , input.nextInt());
            }else if ("g".equals(choose)){
                System.out.println(lru.get(input.nextInt())) ;
            }
            lru.print();
        }
    }
}

第二版 —— 链表+ 散列表(符合要求)

import java.util.HashMap;
import java.util.Scanner;

/**
 * @author gyh
 * @csdn https://blog.csdn.net/qq_40788718
 * @date 2020/8/14 21:31
 */

public class LRUTest {

    static class Node{
        private int key ;
        private int value ;
        private Node pred ;
        private Node next ;

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

    static class LRU{
        private Node head ;

        private Node tail ;
        // 加入 hashMap 用于 查找
        private HashMap<Integer , Node> map ;

        private int capacity ;

        private int size ;

        public LRU(int capacity){
            this.map = new HashMap<>();
            this.capacity = capacity ;
            this.size = 0 ;
            this.head = new Node(-1 , -1) ;
        }

        public int get(int key){
            Node node = map.get(key) ;
            //跳出来可能为空 或者找到key了
            if (node != null){
                delete(node);
                insert(node);
                return node.value ;
            }
            return -1 ;
        }

        public void put(int key , int value){
            //Node node = search(key)
            Node node = map.get(key) ;
            if (node != null){
                node.value = value ;
                return ;
            }

            node = new Node(key , value) ;
            insert(node) ;
            if (size > capacity){
                delete(tail);
            }
        }

        private void insert(Node node){
            Node second = head.next ;
            head.next = node ;
            node.pred = head ;
            node.next = second ;
            if (second != null){
                second.pred = node ;
            }else {
                tail = node ;
            }
            map.put(node.key , node) ;
            this.size ++ ;
        }

        private void delete(Node node){
            if (node == null){
                return ;
            }
            Node pred = node.pred ;
            Node next = node.next ;
            pred.next = next ;
            if (next != null){
                //node不是队尾
                next.pred = pred ;
            }else{
                this.tail = pred ;
            }
            node.pred = null ;
            node.next = null ;
            map.remove(node.key) ;
            this.size -- ;
        }

        public void print(){
            System.out.println("====================");
            Node pre = head.next ;
            while(pre != null){
                System.out.println(pre.key + " " +pre.value);
                pre = pre.next ;
            }
            System.out.println("====================");
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        LRU lru = new LRU(input.nextInt()) ;
        while(input.hasNext()){
            String choose = input.next() ;
            if ("p".equals(choose)){
                lru.put(input.nextInt() , input.nextInt());
            }else if ("g".equals(choose)){
                System.out.println(lru.get(input.nextInt())) ;
            }
            lru.print();
        }
    }
}

第三版 —— 有序散列表(LinkedHashMap)

package ctrip;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Scanner;

/**
 * @author gyh
 * @csdn https://blog.csdn.net/qq_40788718
 * @date 2020/8/14 21:31
 */

public class Third {

    // 省略 LRU


    static class LRULinkedHashMap extends LRU {

        private LinkedHashMap<Integer , Integer> cache ;

        private int capacity = 0 ;

        public LRULinkedHashMap(int capacity){
            super(capacity);
            cache=new LinkedHashMap<Integer,Integer>(capacity,0.75f,true){
                @Override
                protected boolean removeEldestEntry(java.util.Map.Entry<Integer, Integer> eldest) {
                    return size()>capacity;
                }
            };
        }

        @Override
        public int get(int key){
            return cache.getOrDefault(key , -1);
        }

        @Override
        public void put(int key , int value){
            cache.put(key , value) ;
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        LRU lru = new LRULinkedHashMap(input.nextInt()) ;
        while(input.hasNext()){
            String choose = input.next() ;
            if ("p".equals(choose)){
                lru.put(input.nextInt() , input.nextInt());
            }else if ("g".equals(choose)){
                System.out.println(lru.get(input.nextInt())) ;
            }
            lru.print();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值