https://leetcode.com/problems/lfu-cache/#/description
实现一个 Least Frequently Used (LFU),保存访问频率最高的capacity个数,如果要淘汰的可能有多个数频率相同,则淘汰最后一次访问时间最靠前的
lintcode本题测试集不完整
用bucket链表,每个bucket内保存同一个count的所有元素,bucket内部用类似LRU来实现保存元素(head && tail),这样保证在O(1)时间内插入、删除特定元素或者进行淘汰
public class LFUCache {
int capacity;
DListBucket head;
DListBucket tail;
HashMap<Integer, Node> map;
HashMap<Integer, DListBucket> bucketMap;
class DListBucket {
int count;
Node nodeHead;
Node nodeTail;
DListBucket pre;
DListBucket next;
public DListBucket(int count) {
this.count = count;
nodeHead = new Node(0, 0, 0);
nodeTail = new Node(0, 0, 0);
nodeHead.next = nodeTail;
nodeTail.pre = nodeHead;
}
}
class Node {
int key;
int val;
int count;
Node pre;
Node next;
public Node(int key, int val, int count) {
this.key = key;
this.val = val;
this.count = count;
}
}
// @param capacity, an integer
public LFUCache(int capacity) {
// Write your code here
this.capacity = capacity;
head = new DListBucket(Integer.MIN_VALUE);
tail = new DListBucket(Integer.MIN_VALUE);
head.next = tail;
tail.pre = head;
map = new HashMap();
bucketMap = new HashMap();
}
// @param key, an integer
// @param value, an integer
// @return nothing
public void put(int key, int value) {
// Write your code here
if (capacity == 0) {
return;
}
if (map.containsKey(key)) {
Node node = map.get(key);
node.pre.next = node.next;
node.next.pre = node.pre;
DListBucket next = null;
if (bucketMap.get(node.count).next.count != node.count + 1) {
next = insertBucket(node.count + 1, bucketMap.get(node.count));
} else {
next = bucketMap.get(node.count).next;
}
node.count++;
node.val = value;
node.pre = next.nodeTail.pre;
node.next = next.nodeTail;
next.nodeTail.pre = node;
node.pre.next = node;
} else {
Node node = new Node(key, value, 1);
map.put(key, node);
DListBucket next = null;
if (head.next.count != 1) {
next = insertBucket(1, head);
} else {
next = head.next;
}
node.pre = next.nodeTail.pre;
node.next = next.nodeTail;
next.nodeTail.pre = node;
node.pre.next = node;
if (map.size() > capacity) {
removeLastNode(node);
}
}
}
private void removeLastNode(Node cur) {
Node nodeHead = head.next.nodeHead;
Node node = null;
if (nodeHead.next == cur && head.next.next.nodeHead.next != head.next.next.nodeTail) {
node = head.next.next.nodeHead.next;
} else {
node = head.next.nodeHead.next;
}
node.pre.next = node.next;
node.next.pre = node.pre;
map.remove(node.key);
}
public int get(int key) {
// Write your code here
if (!map.containsKey(key)) {
return -1;
}
Node node = map.get(key);
node.pre.next = node.next;
node.next.pre = node.pre;
DListBucket next = null;
if (bucketMap.get(node.count).next.count != node.count + 1) {
next = insertBucket(node.count + 1, bucketMap.get(node.count));
} else {
next = bucketMap.get(node.count).next;
}
node.count++;
node.pre = next.nodeTail.pre;
node.next = next.nodeTail;
next.nodeTail.pre = node;
node.pre.next = node;
return node.val;
}
private DListBucket insertBucket(int count, DListBucket pre) {
DListBucket bucket = new DListBucket(count);
bucket.next = pre.next;
bucket.pre = pre;
pre.next = bucket;
bucket.next.pre = bucket;
bucketMap.put(count, bucket);
return bucket;
}
}