设计LRU缓存结构--题解

设计LRU缓存结构

http://www.nowcoder.com/questionTerminal/e3769a5f49894d49b871c09cadd13a61

写在前面

本题是看着大佬的代码写的,讲讲大佬的思路
https://www.nowcoder.com/profile/797566439

解法

样例 [[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
第一个数字 1 代表 set方法, 2 代表 get方法
第二个第三个 代表 key value
最后一个数字是 k 代表长度 只能容纳多少个key value。
输入的是 每次get的值。 如果找不到就是-1;

本质上还是运用双向链表实现 LRU ,HashMap 只是为了更快的查询到key
图片说明
当我们遇到第一个set方法的时候 就需要插入到head 和tail 之间,
图片说明
每次插入都放在head的后面 因为是最近最少使用嘛,你使用了就放在头结点后面就可以了。最后是这样的链表。
图片说明
当我们遇到get的时候,就把需要被get的结点 给移除,然后放在头结点。
图片说明
遇到需要自动移除结点的时候,就把这个结点移除就OK了,然后新放入的结点还是放在head的后面。

代码

import java.util.*;


public class Solution {
    static class Node{
        int key , value;
        Node prev,next;
        public Node(int key , int value){
            this.key = key;
            this.value = value;
        }
    }
    private Map<Integer,Node> map = new HashMap<>();
    private Node head = new Node(-1,-1);
    private Node tail = new Node(-1,-1);
    private int k;
    public int[] LRU (int[][] operators, int k) {
        // write code here
        this.k = k;
        head.next = tail;
        tail.prev = head;
        int len =(int) Arrays.stream(operators).filter(x->x[0] == 2).count();
        int[] ans = new int[len];
        int cnt = 0;
        for(int i=0;i < operators.length ;i++){
            if(operators[i][0] == 1){
                set(operators[i][1],operators[i][2]);
            }else{
                ans[cnt++] = get(operators[i][1]);
            }
        }
        return ans;
    }
    public void set(int key,int value){
        if(get(key) > -1){
            map.get(key).value = value;
        }else{
            if(map.size() == k ){
                int rk = tail.prev.key;
                tail.prev.prev.next = tail;
                tail.prev = tail.prev.prev;
                map.remove(rk);
            }
            Node node = new Node(key,value);
            map.put(key,node);
            removeToHead(node);
        }
    }
    public int get(int key){
        if(map.containsKey(key)){
            Node node = map.get(key);
            node.prev.next = node.next;
            node.next.prev = node.prev;

            removeToHead(node);
            return node.value;
        }
        return -1;
    }
    public void removeToHead(Node node){
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
        node.prev = head;
    }
}
全部评论
而且这个题的set代码确实存在问题,因为输入的value值可以是负数,所以>-1这个判定不怎么合理,但是巧合的是,else里的操作同样适用于覆盖选项,因为链表同时存在两个链表的时候,map中却只有最新的链表的值,所以不会报错
2 回复 分享
发布于 2020-12-08 20:21
set方法中,若是存在当前值,就应该把这个值放在最常用的值上,就是head后面的值
1 回复 分享
发布于 2020-12-08 20:00
(int) Arrays.stream(operators).filter(x->x[0] == 2).count(); 请问这一句是什么意思呀
点赞 回复 分享
发布于 2020-09-11 09:56
36行应该有一步操作,将这个node放到head下一个节点
点赞 回复 分享
发布于 2020-10-12 13:22
感谢大佬,能理解原理了
点赞 回复 分享
发布于 2020-12-14 21:06
请问相同key值set方法是将新值覆盖掉旧值吗?
点赞 回复 分享
发布于 2021-09-03 15:29
这能保证get set是常数复杂度吗?我觉得不可能。get hashmap也没法保证是常数,最差情况是O(n)
点赞 回复 分享
发布于 2021-09-23 00:10

相关推荐

10-13 17:47
门头沟学院 Java
wulala.god:图一那个善我面过,老板网上找的题库面的
点赞 评论 收藏
分享
26 4 评论
分享
牛客网
牛客企业服务