Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted. Follow up:
Could you do both operations in O(1) time complexity? Example: LFUCache cache = new LFUCache( 2 /* capacity */ ); cache.set(1, 1);
cache.set(2, 2);
cache.get(1); // returns 1
cache.set(3, 3); // evicts key 2
cache.get(2); // returns -1 (not found)
cache.get(3); // returns 3.
cache.set(4, 4); // evicts key 1.
cache.get(1); // returns -1 (not found)
cache.get(3); // returns 3
cache.get(4); // returns 4

referred to: https://discuss.leetcode.com/topic/69137/java-o-1-accept-solution-using-hashmap-doublelinkedlist-and-linkedhashset

Two HashMaps are used, one to store <key, value> pair, another store the <key, node>.
I use double linked list to keep the frequent of each key. In each double linked list node, keys with the same count are saved using java built in LinkedHashSet. This can keep the order.
Every time, one key is referenced, first find the current node corresponding to the key, If the following node exist and the frequent is larger by one, add key to the keys of the following node, else create a new node and add it following the current node.
All operations are guaranteed to be O(1).

 public class LFUCache {
int cap;
ListNode head;
HashMap<Integer, Integer> valueMap;
HashMap<Integer, ListNode> nodeMap; public LFUCache(int capacity) {
this.cap = capacity;
this.head = null;
this.valueMap = new HashMap<Integer, Integer>();
this.nodeMap = new HashMap<Integer, ListNode>();
} public int get(int key) {
if (valueMap.containsKey(key)) {
increaseCount(key);
return valueMap.get(key);
}
return -1;
} public void set(int key, int value) {
if (cap == 0) return;
if (valueMap.containsKey(key)) {
valueMap.put(key, value);
increaseCount(key);
}
else {
if (valueMap.size() < cap) {
valueMap.put(key, value);
addToHead(key);
}
else {
removeOld();
valueMap.put(key, value);
addToHead(key);
}
} } public void increaseCount(int key) {
ListNode node = nodeMap.get(key);
node.keys.remove(key);
if (node.next == null) {
node.next = new ListNode(node.count+1);
node.next.prev = node;
node.next.keys.add(key);
}
else if (node.next.count == node.count + 1) {
node.next.keys.add(key);
}
else {
ListNode newNode = new ListNode(node.count+1);
newNode.next = node.next;
node.next.prev = newNode;
newNode.prev = node;
node.next = newNode;
node.next.keys.add(key);
}
nodeMap.put(key, node.next);
if (node.keys.size() == 0) remove(node);
} public void remove(ListNode node) {
if (node.next != null) {
node.next.prev = node.prev;
}
if (node.prev != null) {
node.prev.next = node.next;
}
else { // node is head
head = head.next;
}
} public void addToHead(int key) {
if (head == null) {
head = new ListNode(1);
head.keys.add(key);
}
else if (head.count == 1) {
head.keys.add(key);
}
else {
ListNode newHead = new ListNode(1);
head.prev = newHead;
newHead.next = head;
head = newHead;
head.keys.add(key);
}
nodeMap.put(key, head);
} public void removeOld() {
if (head == null) return;
int old = 0;
for (int keyInorder : head.keys) {
old = keyInorder;
break;
}
head.keys.remove(old);
if (head.keys.size() == 0) remove(head);
valueMap.remove(old);
nodeMap.remove(old);
} public class ListNode {
int count;
ListNode prev, next;
LinkedHashSet<Integer> keys;
public ListNode(int freq) {
count = freq;
keys = new LinkedHashSet<Integer>();
prev = next = null;
}
}
} /**
* Your LFUCache object will be instantiated and called as such:
* LFUCache obj = new LFUCache(capacity);
* int param_1 = obj.get(key);
* obj.set(key,value);
*/

Summary of LinkedHashSet: http://www.programcreek.com/2013/03/hashset-vs-treeset-vs-linkedhashset/

A Set contains no duplicate elements. That is one of the major reasons to use a set. There are 3 commonly used implementations of Set: HashSet, TreeSet and LinkedHashSet. When and which to use is an important question. In brief, if you need a fast set, you should use HashSet; if you need a sorted set, then TreeSet should be used; if you need a set that can be store the insertion order, LinkedHashSet should be used.

1. Set Interface

Set interface extends Collection interface. In a set, no duplicates are allowed. Every element in a set must be unique. You can simply add elements to a set, and duplicates will be removed automatically.

2. HashSet vs. TreeSet vs. LinkedHashSet

HashSet is Implemented using a hash table. Elements are not ordered. The add, remove, and contains methods have constant time complexity O(1).

TreeSet is implemented using a tree structure(red-black tree in algorithm book). The elements in a set are sorted, but the add, remove, and contains methods has time complexity of O(log (n)). It offers several methods to deal with the ordered set like first(), last(), headSet(), tailSet(), etc.

LinkedHashSet is between HashSet and TreeSet. It is implemented as a hash table with a linked list running through it, so it provides the order of insertion. The time complexity of basic methods is O(1).

3. TreeSet Example

TreeSet<Integer> tree = new TreeSet<Integer>();
tree.add(12);
tree.add(63);
tree.add(34);
tree.add(45);
 
Iterator<Integer> iterator = tree.iterator();
System.out.print("Tree set data: ");
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}

Output is sorted as follows:

Tree set data: 12 34 45 63 

4. HashSet Example

HashSet<Dog> dset = new HashSet<Dog>();
dset.add(new Dog(2));
dset.add(new Dog(1));
dset.add(new Dog(3));
dset.add(new Dog(5));
dset.add(new Dog(4));
Iterator<Dog> iterator = dset.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}

Output:

5 3 2 1 4

Note the order is not certain.

5. LinkedHashSet Example

LinkedHashSet<Dog> dset = new LinkedHashSet<Dog>();
dset.add(new Dog(2));
dset.add(new Dog(1));
dset.add(new Dog(3));
dset.add(new Dog(5));
dset.add(new Dog(4));
Iterator<Dog> iterator = dset.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}

The order of the output is certain and it is the insertion order:

2 1 3 5 4 

Leetcode: LFU Cache && Summary of various Sets: HashSet, TreeSet, LinkedHashSet的更多相关文章

  1. Set集合[HashSet,TreeSet,LinkedHashSet],Map集合[HashMap,HashTable,TreeMap]

    ------------ Set ------------------- 有序: 根据添加元素顺序判定, 如果输出的结果和添加元素顺序是一样 无序: 根据添加元素顺序判定,如果输出的结果和添加元素的顺 ...

  2. [LeetCode] LFU Cache 最近最不常用页面置换缓存器

    Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...

  3. LeetCode LFU Cache

    原题链接在这里:https://leetcode.com/problems/lfu-cache/?tab=Description 题目: Design and implement a data str ...

  4. Java容器---Set: HashSet & TreeSet & LinkedHashSet

    1.Set接口概述        Set 不保存重复的元素(如何判断元素相同呢?).如果你试图将相同对象的多个实例添加到Set中,那么它就会阻止这种重复现象. Set中最常被使用的是测试归属性,你可以 ...

  5. [LeetCode] 460. LFU Cache 最近最不常用页面置换缓存器

    Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ...

  6. leetcode 146. LRU Cache 、460. LFU Cache

    LRU算法是首先淘汰最长时间未被使用的页面,而LFU是先淘汰一定时间内被访问次数最少的页面,如果存在使用频度相同的多个项目,则移除最近最少使用(Least Recently Used)的项目. LFU ...

  7. [LeetCode] LRU Cache 最近最少使用页面置换缓存器

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  8. LeetCode Monotone Stack Summary 单调栈小结

    话说博主在写Max Chunks To Make Sorted II这篇帖子的解法四时,写到使用单调栈Monotone Stack的解法时,突然脑中触电一般,想起了之前曾经在此贴LeetCode Al ...

  9. LFU Cache

    2018-11-06 20:06:04 LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”. ...

随机推荐

  1. CodeForces 13E 分块

    题目链接:http://codeforces.com/problemset/problem/13/E 题意:给定n个弹簧和每个弹簧初始的弹力a[].当球落在第i个位置.则球会被弹到i+a[i]的位置. ...

  2. pandas 学习(2): pandas 数据结构之DataFrame

    DataFrame 类型类似于数据库表结构的数据结构,其含有行索引和列索引,可以将DataFrame 想成是由相同索引的Series组成的Dict类型.在其底层是通过二维以及一维的数据块实现. 1.  ...

  3. 【BZOJ1688】[Usaco2005 Open]Disease Manangement 疾病管理 状压DP

    [BZOJ1688][Usaco2005 Open]Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) ...

  4. jQueryt过滤选择器

    jQueryt过滤选择器 基本过滤选择器 选择器 描述 返回 示例 重要 :first 返回第一个元素 单个元素     :last 返回最后一个元素 单个元素     :not(selector) ...

  5. osg矩阵变换节点-----平移旋转缩放

    osg矩阵变换节点-----平移旋转缩放 转自:http://www.cnblogs.com/ylwn817/articles/1973396.html 平移旋转缩放这个三个是osg矩阵操作中,最常见 ...

  6. About_类与对象03

    php中的static: 1:属于静态变量:: 2:是全部类的属性: 3:调用静态变量要用::(两个冒号). eg:1 <html> <head> <title>s ...

  7. jQuery命名空间,插件开发

    jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...

  8. 一起来做chrome扩展《AJAX请求》

    chrome在一次更新之后,出于安全考虑,完全的禁止了content_script从https向http发起ajax请求,即使正常情况下也会在console里给出提示.这对于WEB来讲是好事,但对于扩 ...

  9. frag General URL components

    HTTP: The Definitive Guide 2.2.7 Fragments Some resource types, such as HTML, can be divided further ...

  10. Linq分组

    1.lin语句 int[] nums = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0, 3 }; DataTable table = new DataTable("Numb ...