当前位置:网站首页>460. LFU cache bidirectional linked list
460. LFU cache bidirectional linked list
2022-07-02 05:27:00 【Empress Yu】
460. LFU cache
Please help me The least used (LFU) Cache algorithm design and implementation of data structure .
Realization
LFUCache
class :
LFUCache(int capacity)
- With the capacity of the data structurecapacity
Initialize objectint get(int key)
- If keykey
In the cache , Then get the value of the key , Otherwise return to-1
.void put(int key, int value)
- If keykey
Already exists , Then change its value ; If the key doesn't exist , Please insert key value pair . When the cache reaches its capacitycapacity
when , Before inserting a new item , Remove the least frequently used items . In this question , When there is a draw ( That is, two or more keys have the same frequency of use ) when , It should be removed Most recently unused Key .To determine the least frequently used keys , You can maintain one for each key in the cache Use counter . The key with the lowest count is the key that has not been used for the longest time .
When a key is first inserted into the cache , Its usage counter is set to
1
( because put operation ). Execute... On the key in the cacheget
orput
operation , Using the counter will increment the value .function
get
andput
Must beO(1)
The average time complexity of running .Example :
Input : ["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]] Output : [null, null, null, 1, null, -1, 3, null, -1, 3, 4] explain : // cnt(x) = key x Use count of // cache=[] The order of last use will be displayed ( The leftmost element is the closest ) LFUCache lfu = new LFUCache(2); lfu.put(1, 1); // cache=[1,_], cnt(1)=1 lfu.put(2, 2); // cache=[2,1], cnt(2)=1, cnt(1)=1 lfu.get(1); // return 1 // cache=[1,2], cnt(2)=1, cnt(1)=2 lfu.put(3, 3); // Remove the key 2 , because cnt(2)=1 , Use the minimum count // cache=[3,1], cnt(3)=1, cnt(1)=2 lfu.get(2); // return -1( Not found ) lfu.get(3); // return 3 // cache=[3,1], cnt(3)=2, cnt(1)=2 lfu.put(4, 4); // Remove the key 1 ,1 and 3 Of cnt identical , but 1 Not used for a long time // cache=[4,3], cnt(4)=1, cnt(3)=2 lfu.get(1); // return -1( Not found ) lfu.get(3); // return 3 // cache=[3,4], cnt(4)=1, cnt(3)=3 lfu.get(4); // return 4 // cache=[3,4], cnt(4)=2, cnt(3)=3Tips :
0 <= capacity <= 10^4
0 <= key <= 10^5
0 <= value <= 10^9
- Call at most
2 * 105
Timeget
andput
Methodsource : Power button (LeetCode)
link :https://leetcode.cn/problems/lfu-cache
Copyright belongs to the network . For commercial reprint, please contact the official authority , Non-commercial reprint please indicate the source .
The result of doing the question
success , It's not hard to , Two way linked list question , and LRU almost . I didn't have the courage to do this before , because The least used This awkward concept , It sounds like a headache . In fact, that is The least used ones are eliminated , In order to ensure that the memory consumption will not be too large
Method : Double linked list
WA summary
- 0 Long processing , Note that the capacity can be 0,WA 了
- key Existing situation , No updates value Value
Method : Double linked list
- Use leading and trailing pointers as boundaries
- Each node needs to record ( key , value , The frequency of , Latest time )
- Record key -> node mapping
- Record The frequency of -> The last node of this frequency mapping , In the initial situation, insert the head node , The frequency is 0
- get
- No element returned -1
- Update element frequency ( Let's take the previous frequency time be called Old frequency , time+1 be called New frequency ), Latest time
- Update element location
- Assume that the current element is the last element of the old frequency , Then remove , At the same time, put the previous node into the last element of the frequency of the previous node 【 There is no need to judge whether the frequency is the same , The same will add new nodes , Not the same 】
- If there are new frequency nodes , Then remove the node from its old location , At the same time, add to the next node of the last node before the new frequency 【1(1 Time )->2(2 Time ), increase 1 The interview of , After the update 2(2 Time )->1(2 Time ), because 1 Is the latest , At the same frequency , In the last 】
- If there is no new frequency node , But after removal , There are still old frequency nodes , Then move to the old frequency node , Behind the last node 【1(1 Time )->2(1 Time ), increase 1 The interview of , After the update 2(1 Time )->1(2 Time ),1 Put it after the next higher grade 】
- Other situations with intervals , The relative position has not changed , Do not move nodes 【2(1 Time )->1(2 Time )->5(4 Time ), increase 1 The number of times ,2(1 Time )->1(3 Time )->5(4 Time )】, Constant relative position
- put
- Capacity of 0, Do not add or process
- The capacity reaches the upper limit , Delete the first element , Note that the element at the end of the processing frequency is removed , Remove from the linked list and hash
- Update node value and latest time
- Update element location ( Same as get)
- In fact, the whole process does not need to maintain the latest time , The node has been maintained when it is added
class LFUCache {
Node first,last;// The head and tail nodes of a two-way linked list
int capacity;// size
Map<Integer,Node> map = new HashMap<>();// key -> node
Map<Integer,Node> timeLast = new HashMap<>();// The last element corresponding to frequency
public LFUCache(int capacity) {
first = new Node(-1,0,0);
last = new Node(-1,0,Integer.MAX_VALUE);
first.next = last;
last.prev = first;
this.capacity = capacity;
timeLast.put(0,first);
}
int curr = 0;// Current timestamp , It is defined as adding 1
public int get(int key) {
if(!map.containsKey(key)) return -1;
Node node = map.get(key);
node.last = ++curr;
move(node);
return map.get(key).val;
}
/**
* Add links
* @param prev Previous node
* @param curr Current node
*/
private void addLink(Node prev,Node curr){
Node next = prev.next;
curr.prev = prev;
curr.next = next;
prev.next = curr;
next.prev = curr;
}
/**
* Remove links , Pay attention to the processing of empty before and after the new node
* @param node Current node
*/
private void removeLink(Node node){
if(node.prev == null) return;
Node pre = node.prev;
Node nex = node.next;
node.prev = null;
node.next = null;
pre.next = nex;
nex.prev = pre;
}
public void put(int key, int value) {
//0 Long term situation handling (WA1)
if(capacity==0) return;
// Full capacity removal
if(!map.containsKey(key) && map.size()==capacity){
Node delNode = first.next;
removeTime(delNode);
removeLink(delNode);
map.remove(delNode.key);
}
Node node=map.getOrDefault(key,new Node(key,value,curr));
node.last = ++curr;
node.val = value;// Be careful , If there is no such sentence , The node cannot update the value in the future (WA2)
move(node);
map.put(key,node);
}
private void removeTime(Node node){
if(timeLast.getOrDefault(node.times,first).key==node.key){
timeLast.remove(node.times);
// If the previous node and the removed node are at the same level , Then this operation will take effect ; Otherwise, different levels , This operation does not take effect , No new value added
timeLast.put(node.prev.times,node.prev);
}
}
private void move(Node node){
// Assume that the current node is the last element of the current number , Delete
removeTime(node);
node.times++;
// If there are elements in the new level , Then the new element is placed at the last of the next level
if(timeLast.containsKey(node.times)){
removeLink(node);
Node prev = timeLast.get(node.times);
addLink(prev,node);
// If there are elements in the old level , Put it after the last element of the old level
}else if(timeLast.containsKey(node.times-1)){
removeLink(node);
Node prev = timeLast.get(node.times-1);
addLink(prev,node);
}
// The current element must be the last element of the new frequency , Replace the last element of the next level
timeLast.put(node.times,node);
}
class Node{
Node prev;
Node next;
int key;// key
int val;// value
int times;// frequency
int last;// The last time
public Node(int key,int val,int last){
this.key = key;
this.val = val;
this.last = last;
times = 0;
}
}
}
Time complexity :O(1)
Spatial complexity :O(n), You need to save various information of the node
边栏推荐
- Simply encapsulate JS and apply it
- LS1046nfs挂载文件系统
- Gee: remote sensing image composite and mosaic
- 来啦~ 使用 EasyExcel 导出时进行数据转换系列新篇章!
- Gee: explore the characteristics of precipitation change in the Yellow River Basin in the past 10 years [pixel by pixel analysis]
- Fabric. JS upload local image to canvas background
- "Original, excellent and vulgar" in operation and maintenance work
- 运维工作的“本手、妙手、俗手”
- Fabric.js 更换图片的3种方法(包括更换分组内的图片,以及存在缓存的情况)
- H5 jump applet
猜你喜欢
随机推荐
LeetCode 1175. Prime number arrangement (prime number judgment + Combinatorial Mathematics)
Storage of data
黑马笔记---Set系列集合
Fabric.js 居中元素
Briefly introduce chown command
Fabric. JS iText superscript and subscript
Fabric.js 背景不受视口变换影响
Gee series: Unit 1 Introduction to Google Earth engine
Gee: remote sensing image composite and mosaic
来啦~ 使用 EasyExcel 导出时进行数据转换系列新篇章!
Gee series: unit 8 time series analysis in Google Earth engine [time series]
7.1模擬賽總結
There are duplicate elements in leetcode. Go implementation
Disable access to external entities in XML parsing
el form 表单validate成功后没有执行逻辑
XSS basic content learning (continuous update)
7.1模拟赛总结
Fabric. JS upload local image to canvas background
Disable access to external entities in XML parsing
7. Eleven state sets of TCP