设计LRU缓存结构
设计LRU缓存结构
示例1
输入: [[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)变为最不常使用的记录
LUR
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
解题思路
数据结构:map+双向链表
HashMap<key,Node>
题目要求set、get操作都为O(1),对于get操作,我们自然想到用map可以解决。set操作,需要考虑题目的LRU特性,则我们需要有一个优先级的属性,自然想到了队列、链表这种结构,用位置来表达优先级。但是这种单向线性结构,remove()的操作需要先查找位置,复杂度为O(n),所以需要使用双向链表。
而get(key)操作:在map中找是否有此节点,如果有则返回节点value,并将此节点移动到最前,没有就返回-1
而put(node)操作:在map中找到是否有此节点,有此节点就将此节点放到最前,没有就建立节点,如果链表长度大于等于链表于容量时删除最后一个,在把当前节点放到前面反之就直接把节点放到最前。
代码
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
//初始化LUR
LURcache lurcache=new LURcache(k);
List<Integer> list = new ArrayList<>();
for(int i=0;i<operators.length;i++){
if(operators[i][0]==1){
lurcache.put(operators[i][1],operators[i][2]);
}else{
list.add(lurcache.get(operators[i][1]));
}
}
int[] res =new int[list.size()];
for(int i=0;i<list.size();i++){
res[i]=list.get(i);
}
return res;
}
}
class LURcache{
//定义双向链表
class Node{
int key,value;
Node pre,next;
public Node(int key,int value){
this.key=key;
this.value=value;
}
}
//HashMap记录节点key,value
Map<Integer,Node> map = new HashMap<>();
//记录链表长度
int size=0;
//定义双向链表的头尾节点
Node head = new Node(-1,-1);
Node tail = new Node(-1,-1);
//容量
int cap;
//从链表得到
public int get(int key){
Node node=map.get(key);
//看在链表中即map中是否有此节点,如果有就将此节点放到最前,如果没就返回-1
if(node==null){
return -1;
}
move(node);
return node.value;
}
public void put(int key,int value){
Node node = map.get(key);
if(node==null){
//当链表中不存在即map中不存在这个节点时构建新节点
Node cur = new Node(key,value);
//如果链表的长度大于容量时删除最后一个,在把当前节点放到前面
//反之就直接把节点放到最前
if(size<cap){
insertFirst(cur);
}else{
delete(tail.pre);
insertFirst(cur);
}
}else{
//当有这个节点时,把这个节点更新这个节点并移动到最前面即删除最后加到最前
node.value=value;
move(node);
}
}
//移动
private void move(Node node){
delete(node);
insertFirst(node);
}
//删除
private void delete(Node node){
map.remove(node.key);
node.pre.next=node.next;
node.next.pre=node.pre;
size--;
}
//增加
private void insertFirst(Node node){
map.put(node.key,node);
node.next=head.next;
head.next.pre=node;
head.next=node;
node.pre=head;
size++;
}
public LURcache(int cap) {
this.cap=cap;
head.next=tail;
tail.pre=head;
tail.next=null;
}
}