一、题目
设计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,输出一个答案
二、实现
import java.util.*;
public class Solution {
/**
* lru design
* @param operators int整型二维数组 the ops
* @param k int整型 the k
* @return int整型一维数组
*/
static class Node{ //节点结构
int key,val;
Node pre,next;
public Node(int key,int val){
this.key = key;
this.val = val;
}
}
private Map<Integer, Node> map = new HashMap<>();
private Node head = new Node(-1,-1); //头
private Node tail = new Node(-1,-1); //尾
private int k;
// 一、设计LRU缓存结构。 k表示缓存结构的容量
public int[] LRU (int[][] operators, int k) {
// write code here
this.k = k;
//1. 初始化缓存结构(指头头和尾)
head.next = tail;
tail.pre = head;
//2. 获取get操作的次数(即第一列数字为2)
int len = (int)Arrays.stream(operators).filter(x->x[0] == 2).count();
int[] res = new int[len]; //结果集合
//3. 遍历数组operators,执行相应的操作
for(int i=0,j=0;i<operators.length;i++){
if(operators[i][0]==1){//set操作
set(operators[i][1],operators[i][2]);
}else{// get操作
res[j++] = get(operators[i][1]);
}
}
return res;
}
// 二、get操作
public int get(int key){
if(map.containsKey(key)){
Node node = map.get(key);
//1. 先将节点从当前位置移除
node.pre.next = node.next;
node.next.pre = node.pre;
//2. 将节点插入头部
moveToHead(node);
//3. 返回获取的值
return node.val;
}
//4. 不存在
return -1;
}
// 三、set操作
public void set(int key, int val){
//1. 该键已存在,只需更新其值
if(get(key)>-1){
map.get(key).val = val;
}
else{// 2. 不存在该键
//2.1 没有存储空间,移除最后一个
if(map.size()== k){//已满,移除最后一个
int nodeK = tail.pre.key; //最后一个节点的key值
tail.pre.pre.next = tail;
tail.pre = tail.pre.pre;
map.remove(nodeK); //从map集合移除
}
//2.2 加入新的元素
Node newNode = new Node(key,val);
map.put(key,newNode);
moveToHead(newNode); //将加入的元素放到第一个位置
}
}
// 四、将节点移到头部的操作
public void moveToHead(Node node){
node.next = head.next;
node.pre = head;
head.next.pre = node;
head.next = node;
}
}