首先,我们先来看一下LRU缓存结构是什么
LRU是Least Recently Used 的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。
有两操作:
set(key,value) 插入操作,缓存区有限定的大小,如果已满的话,需要将最近最久未使用的页面淘汰以后再插入。
get(key) 查找给定的key对应的value是什么
例:缓存区大小为3
set(1,2)
set(2,5)
set(3,2)
get(1)
set(4,1)
get(2)
一开始 我们放入(1,2),(2,5),(3,2),然后查询key = 1之后(2,5),(3,2),(1,2),1变成最近访问过的了。
再想插入(4,1),但是目前缓存区满了。要淘汰掉一个,最近最久未使用的页面是(2,5),那就淘汰(2,5)、变成(3,2),(1,2),(4,1)
之后想查询key=2,但是目前缓存区里没有key=2的界面,那就返回-1。
要求set操作和get操作的时间复杂度都是 O(1),get操作O(1)复杂度比较好说,就是查找key对应的value的话,我们语言中直接有对应的容器的实现,比如c++中的unordered_map,java中的hashmap,python中的dict,都可以直接通过key查找到对应的value
然后就是怎么样才能知道哪个页面是最近最近未使用的页面了。以及进行get操作以后,对应的key是被使用过了。所以要更新一下这个结点的状态。
那我们怎么进行这个操作呢?每次新插入一个结点的时候,我们把这个结点放在双端链表的末尾,进行get操作查询某个key的时候,也把key对应的结点放在双端链表的末尾。
为了能快速的找到一个key对应的结点,我们的map里的存的键值对是<key,node>。node里存了value,前后指针。这样的话,我们就可以通过O(1)的复杂度来完成get和set操作了。
c++
class Solution {
public:
struct node{
int key;
int value;
node* pre = NULL;
node* next = NULL;
};
unordered_map<int,node*> M;
node* front;
node* end;
void push_back(node* val)
{
node* pre = end->pre;
pre->next = val;
val->pre = pre;
val->next = end;
end->pre = val;
}
void delete_front()
{
node* first = front->next;
if(first == end){return;}//如果链表中没有元素,不删除
M.erase(first->key);
front->next = first->next;
first->next->pre = front;
delete first;
}
vector<int> LRU(vector<vector<int> >& operators, int k) {
front = new node;
end = new node;
front->next = end;
end->pre = front;
end->key = -1;
vector<int> ans;
for(int i = 0 ; i < operators.size() ; i++)
{
if(operators[i][0] == 1)//插入操作
{
node *t = new node;
t->key = operators[i][1];
t->value = operators[i][2];
t->next = NULL;
if(M.size() < k)//可以直接插入
{
M[t->key] = t;
push_back(t);
}
else{//要替换一下,先把链表最前面的元素删掉,然后把节点放到链表后面
delete_front();
M[t->key] = t;
push_back(t);
}
}
else if(operators[i][0] == 2)//查询操作
{
//先把要查询的key对应的value查出来
if(M.count(operators[i][1])>0)//如果存在这个节点
{
node * t = M[operators[i][1]];
ans.push_back(t->value);
//把当前的t节点删掉,然后放到队列的末尾
node * pre = t->pre;
pre->next = t->next;
pre->next->pre = pre;
push_back(t);
}
else{//不存在返回-1
ans.push_back(-1);
}
}
}
return ans;
}
};java
import java.util.*;
public class Solution {
class Node {
int key;
int value;
Node pre = null;
Node next = null;
}
HashMap<Integer, Node> M = new HashMap<Integer, Node>();
static Node head;
static Node tail;
static void delete(Node now) {
Node PRE = now.pre;
Node NEXT = now.next;
PRE.next = NEXT;
NEXT.pre = PRE;
}
static void insertLast(Node now) {
Node PRE = tail.pre;
PRE.next = now;
now.pre = PRE;
now.next = tail;
tail.pre = now;
}
public int[] LRU (int[][] operators, int k) {
int count = 0;
ArrayList<Integer> ans = new ArrayList<>();
head = new Node();
tail = new Node();
head.next = tail;
tail.pre = head;
for (int i = 0; i < operators.length; i++) {
int op = operators[i][0];
if (op == 1) { // set
if (count < k) {
count++;
} else { // 删除链表首位元素
Node first = head.next;
M.remove(first.key);
delete(first);
}
// 插入当前元素
Node now = new Node();
now.key = operators[i][1];
now.value = operators[i][2];
M.put(operators[i][1], now);
insertLast(now);
} else if (op == 2) { // get
int key = operators[i][1];
// 看一下有没有对应的key
if (!M.containsKey(key)) {
ans.add(-1);
} else {
// 查对应value,放入
Node now = M.get(key);
ans.add(now.value);
// 把当前节点移到链表末尾
delete(M.get(key));
insertLast(M.get(key));
}
}
}
int[] result = new int[ans.size()];
for (int i = 0; i < ans.size(); i++) {
result[i] = ans.get(i);
}
return result;
}
}

京公网安备 11010502036488号