0%

leetcode 146 Solution

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package com.demo.s146;

import java.util.HashMap;
import java.util.Map;

/**
* LRU 缓存
* 请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。
* 实现 LRUCache 类:
* LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
* int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
* void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
* 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
*
*
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/lru-cache
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
class LRUCache {

//LRU队列中的元素定义 双向链表存储 方便随机访问 删除 添加操作
class DLinkedNode {
//缓存key
int key;
//缓存值
int value;
//队列前一个节点
DLinkedNode prev;
//队列后一个节点
DLinkedNode next;
public DLinkedNode() {}
public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
}
//LRU缓存map<缓存的值, 缓存的元素>
private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
//缓存大小
private int size;
//缓存容量
private int capacity;
//头结点 尾节点
private DLinkedNode head, tail;
//缓存初始化
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
//使用伪头部和伪尾部节点 方便尾部查询,头部删除
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
//查询缓存
public int get(int key) {
//先从map中取
DLinkedNode node = cache.get(key);
if (node == null) {
return -1;
}
//如果 key 存在,先通过哈希表定位,再移到头部, 头插尾删。
moveToHead(node);
return node.value;
}

//存入数据
public void put(int key, int value) {
//先从map中取
DLinkedNode node = cache.get(key);
if (node == null) {
// 如果 key 不存在,创建一个新的节点
DLinkedNode newNode = new DLinkedNode(key, value);
// 添加进哈希表
cache.put(key, newNode);
// 添加至双向链表的头部
addToHead(newNode);
//记录元素个数
++size;
if (size > capacity) {
// 如果超出容量,删除双向链表的尾部节点
DLinkedNode tail = removeTail();
// 删除哈希表中对应的项
cache.remove(tail.key);
--size;
}
}
else {
// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
node.value = value;
moveToHead(node);
}
}

/**
*头插
*/
private void addToHead(DLinkedNode node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
/**
* 删除节点
*/
private void removeNode(DLinkedNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}

/**
* 删除该节点
* 并把该节点移动到头部
*/
private void moveToHead(DLinkedNode node) {
removeNode(node);
addToHead(node);
}

/**
* 删除尾部节点
*/
private DLinkedNode removeTail() {
DLinkedNode res = tail.prev;
removeNode(res);
return res;
}

}
public class Solution {

}