146. LRU Cache && 460. LFU Cache
2016-06-27 13:50
288 查看
146. LRU Cache
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations:getand
put.
get(key)- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value)- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // returns 1 cache.put(3, 3); // evicts key 2 cache.get(2); // returns -1 (not found) cache.put(4, 4); // evicts key 1 cache.get(1); // returns -1 (not found) cache.get(3); // returns 3 cache.get(4); // returns 4
Solution:
Cache all nodes in a DoubleLinkedList. Always pop out from the left, and add from the right.
Use a map to map key to a node.
class LRUCache { private int capacity; private int count = 0; private Map<Integer, CacheNode> cacheMap = new HashMap<>(); private CacheNode LEFT = new CacheNode(0, 0); private CacheNode RIGHT = new CacheNode(0, 0); public LRUCache(int capacity) { this.capacity = capacity; LEFT.right = RIGHT; RIGHT.left = LEFT; } public int get(int key) { CacheNode node = cacheMap.get(key); if (node == null) { return -1; } else { removeNode(node); addNewNode(node); return node.value; } } public void put(int key, int value) { if (capacity == 0) return; CacheNode orig = cacheMap.get(key); CacheNode n = new CacheNode(key, value); addNewNode(n); //add new node to the right cacheMap.put(key, n); if (orig != null) { removeNode(orig); //remove original node. return; } //if capacity is not full if (count < capacity) { ++count; return; } CacheNode evict = LEFT.right; cacheMap.remove(evict.key); removeNode(evict); //removeNode last node. } private void removeNode(CacheNode node) { CacheNode pre = node.left; CacheNode next = node.right; pre.right = next; next.left = pre; } //Add a new node, add it to the end/Right private void addNewNode(CacheNode node) { node.left = RIGHT.left; node.right = RIGHT; RIGHT.left.right = node; RIGHT.left = node; } } class CacheNode { CacheNode left = null; CacheNode right = null; int key = 0; int value = 0; CacheNode(int key, int value) { this.key = key; this.value = value; } }
460. LFU Cache
Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations:getand
put.
get(key)- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(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.put(1, 1); cache.put(2, 2); cache.get(1); // returns 1 cache.put(3, 3); // evicts key 2 cache.get(2); // returns -1 (not found) cache.get(3); // returns 3. cache.put(4, 4); // evicts key 1. cache.get(1); // returns -1 (not found) cache.get(3); // returns 3 cache.get(4); // returns 4 This is just an extension of LRU. LFU is just a map of LRU keyed by the frequency!
/** * !!! Note that both get and put will increase frequency by 1 !!! */ class LFUCache { private int _capacity; private int _count = 0; //To capture the minimum frequency count in the LFU cache //Alternatively, we can link all LRU cache together. private int _leastCount = 0; private Map<Integer, LRUCache> frequencyMap = new HashMap<>(); private Map<Integer, CacheNode> keyMap = new HashMap<>(); public LFUCache(int capacity) { _capacity = capacity; } public int get(int key) { CacheNode node = keyMap.get(key); if (node == null) { return -1; } increaseFreq(node); return node.value; } //remove node from current level and move it to the next level private void increaseFreq(CacheNode node) { LRUCache currentCache = frequencyMap.get(node.count); currentCache.removeNode(node); if (node.count == _leastCount && currentCache.isEmpty()) { ++_leastCount; //we are moving this node to next level } ++node.count; LRUCache nextCache = frequencyMap.computeIfAbsent(node.count, (x) -> new LRUCache()); nextCache.addNewNode(node); } public void put(int key, int value) { CacheNode node = keyMap.get(key); if (node != null) { node.value = value; increaseFreq(node); return; } LRUCache zeroFreqCache = frequencyMap.computeIfAbsent(0, (x) -> new LRUCache()); CacheNode newNode = new CacheNode(key, value, 0); zeroFreqCache.addNewNode(newNode); keyMap.put(key, newNode); if (_count < _capacity) { ++_count; } else { LRUCache cacheToEvict = frequencyMap.get(_leastCount); CacheNode nodeToEvict = cacheToEvict.LEFT.right; keyMap.remove(nodeToEvict.key); cacheToEvict.removeNode(nodeToEvict); } _leastCount = 0; } } class LRUCache { public final CacheNode LEFT = new CacheNode(0, 0, 0); public final CacheNode RIGHT = new CacheNode(0, 0, 0); public LRUCache() { LEFT.right = RIGHT; RIGHT.left = LEFT; } public void removeNode(CacheNode node) { CacheNode pre = node.left; CacheNode next = node.right; pre.right = next; next.left = pre; } public void addNewNode(CacheNode node) { node.left = RIGHT.left; node.right = RIGHT; RIGHT.left.right = node; RIGHT.left = node; } public boolean isEmpty() { return LEFT.right == RIGHT; } } class CacheNode { CacheNode left = null; CacheNode right = null; int key; int value; int count; CacheNode(int key, int value, int count) { this.key = key; this.value = value; this.count = count; } }
相关文章推荐
- 京城游戏人-Day1:一个基于 Unity 的 iOS 互动 Demo
- web api中action的一些写法
- Fresco 专为Android加载图片
- Linux输入输出错误重定向
- 如何利用ZBrush中的DynaMesh创建身体(二)
- XML文档类型定义---DTD文档
- 84.VMware Tools安装——设置共享文件
- 避免常规思维的“我以为”
- MapKit之地理编码和反向地理编码(CLGeocoder、CLPlacemark)
- 20160627常规赛总结
- linux之sed用法
- VS2015添加CyAPI.lib注意事项。
- ios 计算文字高度
- 使用Xcode和Instruments调试解决iOS内存泄露
- 常用CSS代码
- 帝国备份王出现链接不上MYSQL,请设置好数据库相关设置...的解决方案
- 安卓百度地图基本配置及画线路轨迹问题
- 在Windows上面安装NDK,Eclipse上配置NDK
- 纪念我的外婆
- cloudstack 宿主机部署