forked from javadev/LeetCode-in-Java
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLRUCache.java
130 lines (120 loc) · 3.55 KB
/
LRUCache.java
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
package g0101_0200.s0146_lru_cache;
// #Medium #Top_100_Liked_Questions #Top_Interview_Questions #Hash_Table #Design #Linked_List
// #Doubly_Linked_List #Udemy_Linked_List #Big_O_Time_O(1)_Space_O(capacity)
// #2022_06_24_Time_87_ms_(50.80%)_Space_125.2_MB_(58.73%)
import java.util.HashMap;
import java.util.Map;
public class LRUCache {
private static class LruCacheNode {
int key;
int value;
LruCacheNode prev;
LruCacheNode next;
public LruCacheNode(int k, int v) {
key = k;
value = v;
}
}
private int capacity;
private Map<Integer, LruCacheNode> cacheMap = new HashMap<>();
// insert here
private LruCacheNode head;
// remove here
private LruCacheNode tail;
public LRUCache(int cap) {
capacity = cap;
}
public int get(int key) {
LruCacheNode val = cacheMap.get(key);
if (val == null) {
return -1;
}
moveToHead(val);
return val.value;
}
/*
* Scenarios :
* 1. Value key is already present.
* update
* move node to head
* 2. cache is not full
* cache is empty (create node and assign head and tail)
* cache is partially empty (add node to head and update head pointer)
* 3. cache is full
* remove node at tail, update head, tail pointers
* Recursively call put
*
*
* move node to head Scenarios
* 1. node is at head
* 2. node is at tail
* 3. node is in middle
*
*/
public void put(int key, int value) {
LruCacheNode valNode = cacheMap.get(key);
if (valNode != null) {
valNode.value = value;
moveToHead(valNode);
} else {
if (cacheMap.size() < capacity) {
if (cacheMap.size() == 0) {
LruCacheNode node = new LruCacheNode(key, value);
cacheMap.put(key, node);
head = node;
tail = node;
} else {
LruCacheNode node = new LruCacheNode(key, value);
cacheMap.put(key, node);
node.next = head;
head.prev = node;
head = node;
}
} else {
// remove from tail
LruCacheNode last = tail;
tail = last.prev;
if (tail != null) {
tail.next = null;
}
cacheMap.remove(last.key);
if (cacheMap.size() == 0) {
head = null;
}
// Call recursively
put(key, value);
}
}
}
/*
* check for 3 conditions
* 1. node is already at head
* 2. Node is tail node
* 3. Node in middle node
*/
private void moveToHead(LruCacheNode node) {
if (node == head) {
return;
}
if (node == tail) {
tail = node.prev;
}
// node is not head, it should have some valid prev node
LruCacheNode prev = node.prev;
LruCacheNode next = node.next;
prev.next = next;
if (next != null) {
next.prev = prev;
}
node.prev = null;
node.next = head;
head.prev = node;
head = node;
}
}
/*
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/