首先,我们先来看一下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;
    }
}