设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 k ,并有如下两个功能
1. set(key, value):将记录(key, value)插入该结构
2. get(key):返回key对应的value值
提示:
1.某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的,然后都会刷新缓存。
2.当缓存的大小超过k时,移除最不经常使用的记录。
3.输入一个二维数组与k,二维数组每一维有2个或者3个数字,第1个数字为opt,第2,3个数字为key,value
若opt=1,接下来两个整数key, value,表示set(key, value)
若opt=2,接下来一个整数key,表示get(key),若key未出现过或已被移除,则返回-1
对于每个opt=2,输出一个答案
4.为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹
要求:set和get操作复杂度均为 O(1)O(1)
示例1
输入:
[[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
返回值:[1,-1]
说明:
[1,1,1],第一个1表示opt=1,要set(1,1),即将(1,1)插入缓存,缓存是{"1"=1}
[1,2,2],第一个1表示opt=1,要set(2,2),即将(2,2)插入缓存,缓存是{"1"=1,"2"=2}
[1,3,2],第一个1表示opt=1,要set(3,2),即将(3,2)插入缓存,缓存是{"1"=1,"2"=2,"3"=2}
[2,1],第一个2表示opt=2,要get(1),返回是[1],因为get(1)操作,缓存更新,缓存是{"2"=2,"3"=2,"1"=1}
[1,4,4],第一个1表示opt=1,要set(4,4),即将(4,4)插入缓存,但是缓存已经达到最大容量3,移除最不经常使用的{"2"=2},插入{"4"=4},缓存是{"3"=2,"1"=1,"4"=4}
[2,2],第一个2表示opt=2,要get(2),查找不到,返回是[1,-1]
输入:[[1,1,1],[1,2,2],[2,1],[1,3,3],[2,2],[1,4,4],[2,1],[2,3],[2,4]],2
返回值:[1,-1,-1,3,4]
利用java的LinkHashMap来实现,实现比较简单,代码如下
public static int[] firstLRU (int[][] operators, int k) {
// write code here
LinkedHashMap map = new LinkedHashMap<>();
if(operators == null || operators.length < 1 || k < 1){
return null;
}
List list = new ArrayList<>();
for (int i = 0; i < operators.length; i++) {
if(map.size() > k){
Integer next = map.keySet().iterator().next();
map.remove(next);
}
int[] arr = operators[i];
int opt = arr[0];
int key = arr[1];
if(opt == 1){
int value = arr[2];
map.put(key,value);
}else {
Integer integer = map.get(key);
if(integer == null){
list.add(-1);
}else {
map.remove(key);
map.put(key,integer);
list.add(integer);
}
}
}
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
由于第一种解法,我们使用了java自带的工具类LinkHashMap,第二种解法,我们就利用map + 队列来实现。代码如下
public static int[] secondLRU (int[][] operators, int k) {
HashMap map = new HashMap<>();
Queue queue = new LinkedList<>();
List list = new ArrayList<>();
for (int i = 0; i < operators.length; i++) {
if(queue.size() > k){
Integer poll = queue.poll();
map.remove(poll);
}
int[] arr = operators[i];
int opt = arr[0];
int key = arr[1];
if(opt == 1){
int value = arr[2];
queue.add(key);
map.put(key,value);
}else {
Integer integer = map.get(key);
if(integer == null){
list.add(-1);
}else {
list.add(integer);
queue.remove(key);
queue.add(key);
}
}
}
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
由于第一种解法,我们使用了java自带的工具类LinkHashMap,第二种解法,我们利用map + 队列来实现,第三种解法,我们利用map+手动实现链表来解决。代码如下
static Node head = null;
static int count = 0;
public static int[] thirdLRU (int[][] operators, int k) {
if(operators == null || operators.length < 1 || k < 1){
return null;
}
HashMap map = new HashMap<>();
List list = new ArrayList<>();
for (int i = 0; i < operators.length; i++) {
if(count > k){
int remove = deleteHead();
map.remove(remove);
}
int[] arr = operators[i];
int opt = arr[0];
int key = arr[1];
if(opt == 1){
int value = arr[2];
addEnd(key);
map.put(key,value);
}else {
Integer integer = map.get(key);
if(integer == null){
list.add(-1);
}else {
list.add(integer);
deleteByNode(key);
addEnd(key);
}
}
}
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
private static void deleteByNode(Integer key){
Node node = head;
Node pre = null;
if(node == null){
return;
}
while (node != null && !node.item.equals(key)){
pre = node;
node = node.next;
}
if(pre == null){
head = head.next;
}else {
if(node == null){
return;
}else {
pre.next = node.next;
}
}
count--;
}
public static void addEnd(int key){
Node node = new Node(key);
Node tem = head;
count ++;
if(head == null){
head = node;
}else {
while (true){
Node n = tem;
tem = tem.next;
if(tem == null){
n.next = node;
break;
}
}
}
}
private static int deleteHead(){
if(head == null){
return -1;
}
count --;
Integer item = head.item;
head = head.next;
return item;
}
static class Node{
Node next;
Integer item;
public Node(Integer item){
this.item = item;
}
}