0000设计/数据结构中等 LeetCode146. LRU 缓存机制 设计LRU缓存结构

leetcode的LRU题目:146. LRU 缓存机制

问题描述:

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?

分析

构建LRU数据结构,LRU由map、LinkedList构成,还需要一个类Node。
map负责快速找到结点;
LinkedList负责调整访问顺序;
Node有key,value。当删除结点,以及map中的key时,Node中的key就派上用场了,代码如下。
LinkedList有删除指定元素的方法remove(Object o);
因为直接使用LinkedList,没有自己去实现一个双向链表,只要熟悉get,put方发的逻辑,实现起来很简单。

get方法:
存在key,删除原来的结点,重新创建一个结点插入到头部。
不存在key,返回-1

put方法:
存在key,删除原来的结点,重新创建一个结点插入到头部。
不存在key,创建一个新结点插入到头部。判断链表的长度是否超过capacity,如果超过,删除尾部的结点。

Node del = li.pollFirst();
map.remove(del.key);

代码:

推荐的写法,参考牛客网编程高频题3——NC93设计LRU缓存结构

import java.util.*;
public class Solution {
    
    public int[] LRU (int[][] operators, int k) {
        lru lr = new lru(k);
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < operators.length; i++){
            if(operators[i][0] == 1){
                lr.put(operators[i][1],operators[i][2]);
            }
            if(operators[i][0] == 2){
                int tmp = lr.get(operators[i][1]);
                list.add(tmp);
            }
        }
        int[] res = new int[list.size()];
        for(int i = 0; i < res.length; i++){
            res[i] = list.get(i);
        }
        return res;
    }
}
class lru{
    public int capacity;
    public HashMap<Integer,Node> map;
    public LinkedList<Node> li;
    public lru(int size){
        capacity = size;
        map = new HashMap<>();
        li = new LinkedList<>();
    }
    public int get(int k){
        if(map.containsKey(k)){
            put(k,map.get(k).value);
            return map.get(k).value;
        }else{
            return -1;
        }
    }
    public void put(int k, int v){
        Node newNode = new Node(k,v);
        if(map.containsKey(k)){
            li.remove(map.get(k));
            li.offerLast(newNode);
            map.put(k,newNode);
        }else{
            map.put(k,newNode);
            li.offerLast(newNode);
            if(map.size() > capacity){
                Node del = li.pollFirst();
                map.remove(del.key);
            }
        }
    }
}
class Node{
    public int key;
    public int value;
    public Node(int k, int v){
        this.key = k;
        this.value = v;
    }
}
class LRUCache {
    class LRUnode{
        int key;
        int value;
        public LRUnode pre;
        public LRUnode next;
        public LRUnode(){
        };
        public LRUnode(int _key, int _value){
            key = _key;
            value = _value;
        }
    }
    int size;
    int capacity;
    HashMap<Integer,LRUnode> map = new HashMap<>();
    public LRUnode head;
    public LRUnode tail;

    public LRUCache(int capacity) {//有参构造器
        this.size = 0;
        this.capacity = capacity;
        head = new LRUnode();
        tail = new LRUnode();
        head.next = tail;
        tail.pre = head;
    }
    
    public int get(int key) {
        LRUnode tmp = map.get(key);
        if(tmp==null){
            return -1;
        }
        movefirst(tmp);
        return tmp.value;
    }
    
    public void put(int key, int value) {
        LRUnode tmp = map.get(key);
        if(tmp != null){
            tmp.value = value;
            movefirst(tmp);
        }else{
            size++;
            LRUnode newnode = new LRUnode(key, value);
            putnode(newnode);
            map.put(key,newnode);
            if(size > capacity){
                size--;
                LRUnode del = tail.pre;
                delnode(del);
                map.remove(del.key);
            }
        }
    }

    public void delnode(LRUnode node){
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }
    public void putnode(LRUnode node){
        node.next = head.next;
        head.next.pre = node;
        head.next = node;
        node.pre = head;
    }
    public void movefirst(LRUnode node){
    /*一定是先删除后增添!否则结点node不能移动到头部。
    因为先增添会使node有两个,后删除删除的是刚添加的node,原来node的位置并没有移动*/
        delnode(node);
        putnode(node);
    }
}

设计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,输出一个答案

方法一 自行构造LRU数据结构
import java.util.*;

public class Solution {
    class LRUnode{
        int key;
        int value;
        LRUnode pre;
        LRUnode next;
        LRUnode(int k,int v){
            this.key = k;
            this.value = v;
        }
        LRUnode(){
        }
    }
    
    LRUnode head = new LRUnode();
    LRUnode tail = new LRUnode();
    int size;
    int capacity;
    HashMap<Integer,LRUnode> map;
    Solution(){
        
    }
    
    Solution(int capacity){
        this.capacity = capacity;
        this.size = 0;
        head.next = tail;
        tail.pre = head;
        this.map = new HashMap<>();
    }
    
    public int get(int key){
        LRUnode tmp = map.get(key);
        if(tmp != null){
            movefirst(tmp);
            return tmp.value;
        }else{
            return -1;
        }
    }
    
    public void put(int key, int value){
        LRUnode tmp = map.get(key);
        if(tmp != null){
            tmp.value = value;
        }else{
            size++;
            LRUnode xin = new LRUnode(key,value);
            input(xin);
            map.put(key,xin);
            if(size > capacity){
                map.remove(tail.pre.key);
                del(tail.pre);
                size--;
            }
        }
    }
    
    public void input(LRUnode node){
        head.next.pre = node;
        node.next = head.next;
        node.pre = head;
        head.next = node;
    }

    public void del(LRUnode node){
        node.next.pre = node.pre;
        node.pre.next = node.next;
    }

    public void movefirst(LRUnode node){
        del(node);
        input(node);
    }
    public int[] LRU (int[][] operators, int k) {
        Solution s = new Solution(k);
        ArrayList<Integer> li = new ArrayList<>();
        for(int i = 0; i < operators.length; i++){
            if(operators[i][0] == 1){
                s.put(operators[i][1],operators[i][2]);
            }
            if(operators[i][0] == 2){
                int tmp = s.get(operators[i][1]);
                li.add(tmp);
            }
        }
        int[] res = new int[li.size()];
        for(int i = 0; i < li.size(); i++){
            res[i] = li.get(i);
        }
        return res;
    }
}
方法二 利用LinkedHashMap
题解
  1. 利用LinkedHashMap来实现每次访问后的数据排在前面。
    LinkedHashMap相比于HashMap是有序的,他有两种排序方式,一种是按照插入顺序,另一种是按照访问顺序。LRU需要的是后一种,想要实现访问顺序的排序,new LinkedHashMap()需要输入参数true, false表示按照插入顺序。
    在这里插入图片描述
  2. 删除最近最少访问的结点
    LinkedHashMap是尾插入,头部是最旧的结点,所以当超过LRU的最大容量时,删除头结点,即:lru.keySet().iterator().next() 。keySet()键集合,iterator()从头结点开始遍历。
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) {
        LinkedHashMap<Integer,Integer> lru = new LinkedHashMap<>(k,0.75f,true);
        List<Integer> list = new ArrayList<>();
        for(int[] ope : operators){
            int tmp = ope[0];
            int key = ope[1];
            if(tmp == 1){
                if(lru.containsKey(key)){
                    lru.remove(key);
                }else if(lru.size() >= k){
                    lru.remove(lru.keySet().iterator().next());
                }
                lru.put(key,ope[2]);
            }else if(tmp == 2){
                if(lru.containsKey(key)){
                    int value = lru.get(key);
                    lru.remove(key);
                    lru.put(key,value);
                    list.add(value);
                }else {
                    list.add(-1);
                }
            }
        }
        int[] res = new int[list.size()];
        for(int i = 0; i < res.length; i++){
            res[i] = list.get(i);
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值