About 2 min
LRU
hashmap + 全局双链表
hashmap:用来省去遍历链表节点的时间,直接根据key获取到对应节点。
全局双链表:node有属性key。从双链表中选出淘汰结点时,map也需要删除对应节点,从而需要结点的key。
put:
-> map中不存在:[头插结点] [map入]
-> 超容:[链表断尾] [map删除]
-> map中存在:[更新val] [移动到头]
get:
-> map中不存在:返回-1
-> map中存在:[移动到头] [返回val]
class LRUCache {
int capacity;
HashMap<Integer, Node> map = new HashMap<>();
DList dList = new DList();
static class Node {
int key;
int value;
Node next;
Node pre;
public Node() {
}
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
static class DList {
Node head = new Node();
Node tail = new Node();
public DList() {
head.next = tail;
tail.pre = head;
}
public void add(Node added) {
Node first = head.next;
head.next = added;
added.pre = head;
added.next = first;
first.pre = added;
}
public void remove(Node cur) {
cur.pre.next = cur.next;
cur.next.pre = cur.pre;
}
public void setHead(Node m) {
if (m != head.next) {
remove(m);
add(m);
}
}
}
public LRUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
Node m = map.get(key);
if (m == null) {
return -1;
} else {
dList.setHead(m);
return m.value;
}
}
public void put(int key, int value) {
Node m = map.get(key);
if (m == null) {
if (map.size() >= capacity) {
// LRU淘汰就是末尾,直接从双链表中获取。
Node last = dList.tail.pre;
dList.remove(last);
map.remove(last.key);
}
Node added = new Node(key, value);
dList.add(added);
map.put(key, added);
} else {
m.value = value;
dList.setHead(m);
}
}
}
LFU
hashmap + freqMap + 局部双链表
没有全局双链表了,而是 hashmap 存key对应的Node + freqMap 存freq对应的局部双链表。
从key获取hashmap的Node,再用node的freq获取freqMap的局部双链表。
// 460. LFU 缓存
class LFUCache {
int capacity;
HashMap<Integer, Node> map = new HashMap<>();
// 没有全局链表 DList dList = new DList(); 了,而是放在map中的局部链表。
HashMap<Integer, DList> freqMap = new HashMap<>();
static class Node {
int key;
int value;
int freq;
Node next;
Node pre;
public Node() {
}
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
static class DList {
Node head = new Node();
Node tail = new Node();
public DList() {
head.next = tail;
tail.pre = head;
}
public void add(Node added) {
Node first = head.next;
head.next = added;
added.pre = head;
added.next = first;
first.pre = added;
}
public void remove(Node cur) {
cur.pre.next = cur.next;
cur.next.pre = cur.pre;
}
}
int minFreq = 1;
public LFUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
Node m = map.get(key);
if (m == null) {
return -1;
} else {
update(m, null);
return m.value;
}
}
public void put(int key, int value) {
Node m = map.get(key);
if (m == null) {
if (map.size() >= capacity) {
// freqMap删除最小频率的节点,删除局部链表的最后节点
DList dList = freqMap.get(minFreq);
Node last = dList.tail.pre;
if(last != dList.head){
dList.remove(last);
}
// Map也删除
map.remove(last.key);
}
Node added = new Node(key, value);
added.freq = 1;
// map添加
map.put(key, added);
// freq添加
DList dList = freqMap.getOrDefault(1, new DList());
dList.add(added);
freqMap.put(1, dList);
// 最小频率是新增的1
minFreq = 1;
} else {
update(m, value);
}
}
public void update(Node m, Integer value){
// freq删除老频率, 且确保空时加最小频率
DList dList = freqMap.get(m.freq);
dList.remove(m);
if(dList.head.next == dList.tail && m.freq == minFreq){
minFreq++;
}
// freq添加新频率
if(value != null){
m.value = value;
}
m.freq++;
DList dList2 = freqMap.getOrDefault(m.freq, new DList());
dList2.add(m);
freqMap.put(m.freq, dList2);
}
}