leetcode刷题
LRU算法–最近最少使用算法
**解题思路:这道题综合性很强,很多大厂都作为备考题!!!
首先:最近最少使用,它采用的是双向链表+哈希表来实现的。在java中,LinkedHashMap正是这种结构,有兴趣的同学可以去读一下源码~这里就不介绍了。
我们首先要定义一个双向链表DoubleList和节点Node
1.定义Node节点
//由于是双向链表,所以每个Node节点有prev和next两个指针;
//我们存入key和value,因为我们是要put和get的,我们存入到map当中的
class Node{
int key,value;
Node next;
Node prev;
public Node(int key,int value){
this.key = key;
this.value = value;
}
}
2.定义DoubleList双向链表
(1)定义head和tail首尾虚拟节点
(2)定义一个size,来计算节点的个数,因为增加和删除的时候要统计的
(3)因为LRU是最近最少未使用算法,所以我们需要把:每次更改的节点放入到队首,所以我们定义一个addFirst(Node node)方法,!!!不要忘记size++
(4)因为LRU涉及到删除最久未使用的Node,所以我们在定义一个removeLast()方法和remove(Node node)方法
!!!不要忘记size–
class DoubleList{
Node tail;
Node head;
int size;
public DoubleList(){
head = new Node(0,0);//分别对head和tail进行初始化
tail = new Node(0,0);
head.next = tail;
tail.prev = head;
size = 0;
}
//添加第一个节点Node
private void addFirst(Node node){
node.next = head.next;
node.prev = head;
head.next.prev = node;//注意这个位置!!!
head.next = node;//注意这个位置!!!
size++;
}
//删除一个节点Node
private void remove(Node node){
node.prev.next = node.next;
node.next.prev = node.prev;
size--;
}
//删除最后一个节点Node
private Node removeLast(){
//如果当前没有元素,直接返回null即可。
if(tail.prev==head){
return null;
}
Node last = tail.prev;
remove(last);
return last;
}
private int size(){
return size;
}
}
3.定义一个HashMap,存放的是key和value,value存放的是Node节点;在定义一个容量capacity;然后对它们进行初始化
DoubleList cache;
Map<Integer,Node>;
int capacity;
public LRUCache(int capacity) {
cache = new DoubleList();
cache = new HashMap<>();
this.capacity = capacity;
}
4.定义完之后,我们久可以开始写get和put方法了!!
get(int key):分为2种情况
1.如果map中不存在key,则返回-1;
2.如果map种存在key的话,通过get(key).val方法得到值即可。
[我们首先需要把之前的cache的Node删除掉,然后把当前的这个key对应的Node通过addFirst()添加到队首,]==通过put()方法实现
public int get(int key) {
if(!Map.containsKey(key)){
return -1;
}
int value = map.get(key).val;//注意!!!.val因为get(key)得到的是Node
//put方法中存在加入到addFirst方法,所以把key和value都存进去
put(key,value);
return value;
}
4.put(int key,int value)方法
(1)我们首先要把key和value封装为一个Node节点
(2)如果已经存在key了,久是覆盖
(3)如果不存在key,就是插入;但是再插入之前需要判断当前的容量是否够,如果不够要删除最后一个,然后再插入;如果够,久直接插入
public void put(int key, int value) {
Node x = new Node(key,value);
if(map.containsKey(key)){
//cache删除那个key对应的node节点即可。key还是要留着的
cache.remove(map.get(key));
//cache存放的是一个完整的node
cache.addFirst(x);
map.put(key,x);
}else{
if(cache.size()==capacity){
//如果不够了,就要删除cache中的最后一个
map.remove(cache.removeLast().key);
}
//把新的节点x加入到链表头部
cache.addFirst(x);
//把key和节点x加入到map中
map.put(key,x);
}
}
**
完整代码
package 左神.leetcode;
import java.util.HashMap;
import java.util.Map;
public class main10_LRU {
Map<Integer,Node> map;
DoubleLinked cache;
int cap;
public static void main(String[] args) {
main10_LRU lru = new main10_LRU(1);
lru.put_(1,1);
lru.put_(2,2);
int x = lru.get_(1);
System.out.println(x);
}
public main10_LRU(int capacity){
this.cap = capacity;
map = new HashMap<>();
cache = new DoubleLinked();
}
private int get_(int key){
if(!map.containsKey(key)){
return -1;
}
int val = map.get(key).val;
put_(key,val);
return val;
}
private void put_(int key,int value){
Node x = new Node(key,value);
if(map.containsKey(key)){//如果重复了,就把原来的删掉。新的增加到开头
cache.remove(map.get(key));
cache.addFirst(x);
map.put(key,x);
}else{
if (cap==cache.size()){
//map中删除,cache中的最后一个
map.remove(cache.removeLast().key);
}
cache.addFirst(x);
map.put(key,x);
}
}
//构造一个双向链表类
class DoubleLinked{
Node head,tail;
int size;
public DoubleLinked(){
head = new Node(0,0);
tail = new Node(0,0);
head.next = tail;
tail.prev = head;
size = 0;
}
//表头添加一个元素
public void addFirst(Node x){
x.next = head.next;
x.prev = head;
head.next.prev = x;
head.next = x;
size++;
}
//删除链表最后一个元素
public Node removeLast(){
if(tail.prev==head){
return null;
}
Node last = tail.prev;
remove(last);
return last;
}
//删除链表中的x结点
public void remove(Node x){
x.prev.next = x.next;
x.next.prev = x.prev;
size--;
}
public int size(){
return size;
}
}
//双向链表的node结点
class Node{
int key,val;
Node next,prev;
public Node(int key,int val){
this.key = key;
this.val = val;
}
}
}