设计LRU缓存结构

题目

设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能
set(key, value):将记录(key, value)插入该结构
get(key):返回key对应的value值
[要求]
set和get方法的时间复杂度为O(1)
某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。
若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1
对于每个操作2,输出一个答案。

示例:
输入
[[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)变为最不常使用的记录
思路:利用map存储键和值,利用双向链表记录插入到缓存中的数据

  1. 利用java自带的LinkedHashMap,LinkedHashMap有一个重要的特性就是有序性,加入键值对的顺序是怎样的迭代输出就是什么顺序,其内部采用双向链表结构维持顺序。
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
          Map<Integer, Integer> map = new LinkedHashMap<>();
        List<Integer> list = new LinkedList<>();
        for (int[] operator : operators) {
            int key = operator[1];
            switch(operator[0]) {
                case 1: //插入操作  
                    //获取值
                    int value = operator[2];
                    //如果缓存还有空间,直接加入
                    if (map.size() < k) {
                        map.put(key, value);
                    } else {//缓存没有空间,需要弹出一个元素,这里采用的是首元素是最不经常使用
                    	//获取第一个插入的元素
                        Iterator it = map.keySet().iterator();
                        map.remove(it.next());
                        map.put(key, value);
                    }
                    break;
                case 2://获取元素
                    if (map.containsKey(key)) {
                        int val = map.get(key);
                        list.add(val);
                        //移除这个元素并重新插入到链表的尾部
                        map.remove(key);
                        map.put(key, val);
                    } else {
                        list.add(-1);
                    }
                    break;
                default:
            }
        }
        int[] res = new int[list.size()];
        int i = 0;
        for (int val : list) {
            res[i++] = val;
        }
        return res;
    }
}
  1. 自己实现双向链表
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) {
          //存储<key,node>
        Map<Integer,Node> map = new HashMap<>();
        List<Integer> list = new ArrayList<>();
        //尾结点指针
        Node last = null;
        //头指针
        Node head = new Node(-1,-1);
        for(int[] opt:operators) {
            //键
            int key = opt[1];
            switch (opt[0]){
                //如果是set操作,将节点加入head后,并放入map,注意加入的可以是不相同的
                case 1:
                    Node n = new Node(key,opt[2]);
                    map.put(key,n);
                    if(head.next == null) {
                        insertNode(head,n);
                        last = n;
                    } else {
                       insertNode(head,n);
                    }
                    if(map.size() > k) {
                        //移除最后一个元素
                        map.remove(last.key);
                        last = last.pre;
                        last.next = null;

                    }
                 
                    break;
                case 2://如果是get操作
                    Node t = map.get(key);
                    if(t != null) {
                        list.add(t.value);
                        //如果是尾结点且链表有多个节点
                        if(t.next == null && map.size() > 1) {
                            //更新尾结点
                            last = t.pre;
                            last.next = null;
                            //插入到头结点
                            insertNode(head,t);
                        } else if(t.next != null && map.size() > 1) {//如果是中间某个结点且长度大于1
                            Node preNode = t.pre;
                            Node nextNode = t.next;
                            preNode.next = nextNode;
                            nextNode.pre = preNode;
                            insertNode(head,t);
                        }
                    } else {
                        list.add(-1);
                    }
                    //System.out.println("case 2:");
                    //printNode(head);
                    //System.out.println();
                    break;
            }

        }
        int[] res = new int[list.size()];
        int j = 0;
        for (int i : list) {
            res[j++] = i;
        }
        return res;
    }
    //实现插入一个结点到头结点后
    public void insertNode(Node head,Node insertNode) {
        if(head.next == null) {
            head.next = insertNode;
            insertNode.pre = head;
            insertNode.next = null;
        } else {
            Node nextNode = head.next;
            insertNode.next = nextNode;
            nextNode.pre = insertNode;
            head.next = insertNode;
            insertNode.pre = head;
        }
}
}
class Node{
    public Integer key;
    public Integer value;
    public Node pre;
    public Node next;
    public Node(Integer key,Integer value) {
        this.key = key;
        this.value = value;
        this.pre = null;
        this.next = null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值