设计LRU缓存结构

package com.heu.wsq.niuke.top200;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 设计LRU缓存结构
 * @author wsq
 * @date 2021/5/8
 * 设计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],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
 * 输出
 *  [1,-1]
 */
public class LRU {
    public int[] LRU (int[][] operators, int k) {
        // write code here
        List<Integer> list = new ArrayList<>();
        LRUCache lruCache = new LRUCache(k);
        for(int[] op: operators){
            if(op[0] == 1){
                lruCache.set(op[1], op[2]);
            }else if(op[0] == 2){
                list.add(lruCache.get(op[1]));
            }
        }
        int[] ans = new int[list.size()];
        for(int i = 0; i < list.size(); i++){
            ans[i] = list.get(i);
        }
        return ans;
    }
}

class LRUCache{
    /**
     * 双向链表
     */
    class LinkedNode{
        private int key;
        private int value;
        private LinkedNode prev;
        private LinkedNode next;
        public LinkedNode(){}

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

    /**
     * 保存头尾节点的指针,以便于在O(1)时间内进行去除链表尾,和新增节点到链表头
     */
    private LinkedNode head;
    private LinkedNode tail;
    /**
     * 保存key与node的映射,作为缓存表
     */
    private Map<Integer, LinkedNode> cache;
    /**
     * 定义缓存表的容量
     */
    private int capacity;

    public LRUCache(int k){
        this.cache = new HashMap<>();
        this.capacity = k;
        this.head = new LinkedNode();
        this.tail = new LinkedNode();
        this.head.next = this.tail;
        this.tail.prev = this.head;
    }

    /**
     * 添加节点到缓存中
     * 1.当缓存中没有对应的记录信息,则新建一个节点保存到缓存中,并将对应的节点放置到链表的头部
     * 2.当缓存中有对应的记录信息,更新记录节点的value,,并将该记录节点更新到链表的头部,表示该记录最近被使用
     * @param k
     * @param v
     */
    public void set(int k, int v){
        LinkedNode node = this.cache.get(k);
        if(node == null){
            node = new LinkedNode(k, v);
            this.cache.put(k, node);
            addToHead(node);
            if(this.cache.size() > this.capacity){
                LinkedNode tailNode = rmTailNode();
                this.cache.remove(tailNode.key);
            }
        }else{
            node.value = v;
            rmNodeToHead(node);
        }
    }

    /**
     * 通过key获取缓存信息
     * 并且需要更新该记录到链表的头部,表示该缓存记录最近被使用了
     * @param k
     * @return
     */
    public int get(int k){
        LinkedNode node = this.cache.get(k);
        if(node != null){
            rmNodeToHead(node);
        }
        return node == null ? -1 :node.value;
    }

    private void rmNodeToHead(LinkedNode node){
        rmNode(node);
        addToHead(node);
    }
    private void rmNode(LinkedNode node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    private void addToHead(LinkedNode node){
        node.next = this.head.next;
        this.head.next = node;
        node.prev = this.head;
        node.next.prev = node;
    }
    private LinkedNode rmTailNode(){
        LinkedNode node = this.tail.prev;
        rmNode(node);
        return node;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值