Skip to content

Commit 9917fef

Browse files
author
wangpeng
committed
feat: 460_LFUCache
1 parent 99cc6c6 commit 9917fef

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package pp.arithmetic.hard;
2+
3+
import java.util.HashMap;
4+
import java.util.LinkedList;
5+
6+
/**
7+
* Created by wangpeng on 2019-03-07.
8+
* 460. LFU缓存
9+
* <p>
10+
* 设计并实现最不经常使用(LFU)缓存的数据结构。它应该支持以下操作:get 和 put。
11+
* <p>
12+
* get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。
13+
* put(key, value) - 如果键不存在,请设置或插入值。当缓存达到其容量时,它应该在插入新项目之前,使最不经常使用的项目无效。
14+
* 在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,最近最少使用的键将被去除。
15+
* <p>
16+
* 进阶:
17+
* 你是否可以在 O(1) 时间复杂度内执行两项操作?
18+
* <p>
19+
* 示例:
20+
* <p>
21+
* LFUCache cache = new LFUCache( 2 );
22+
* <p>
23+
* cache.put(1,1);
24+
* cache.put(2,2);
25+
* cache.get(1); // 返回 1
26+
* cache.put(3,3); // 去除 key 2
27+
* cache.get(2); // 返回 -1 (未找到key 2)
28+
* cache.get(3); // 返回 3
29+
* cache.put(4,4); // 去除 key 1
30+
* cache.get(1); // 返回 -1 (未找到 key 1)
31+
* cache.get(3); // 返回 3
32+
* cache.get(4); // 返回 4
33+
*
34+
* @see <a href="https://leetcode-cn.com/problems/lfu-cache/">lfu-cache</a>
35+
*/
36+
public class _460_LFUCache {
37+
public static void main(String[] args) {
38+
LFUCache cache = new LFUCache(2);
39+
cache.put(1, 1);
40+
cache.put(2, 2);
41+
System.out.println(cache.get(1)); // 返回 1
42+
cache.put(3, 3); // 去除 key 2
43+
System.out.println(cache.get(2)); // 返回 -1 (未找到key 2)
44+
System.out.println(cache.get(3)); // 返回 3
45+
cache.put(4, 4); // 去除 key 1
46+
System.out.println(cache.get(1)); // 返回 -1 (未找到 key 1)
47+
System.out.println(cache.get(3)); // 返回 3
48+
System.out.println(cache.get(4)); // 返回 4
49+
}
50+
51+
/**
52+
* 执行用时: 238 ms, 在LFU Cache的Java提交中击败了23.53% 的用户
53+
* 内存消耗: 71.7 MB, 在LFU Cache的Java提交中击败了0.00% 的用户
54+
* 使用HashMap + LinkedList的方式实现,时间耗时花在了LinkedList上
55+
*/
56+
private static class LFUCache {
57+
58+
private HashMap<Integer, Node> map = new HashMap<>();
59+
private HashMap<Integer, LinkedList<Integer>> freqMap = new HashMap<>();
60+
int max;
61+
int cur;
62+
int minFreq;
63+
64+
public LFUCache(int capacity) {
65+
max = capacity;
66+
}
67+
68+
public int get(int key) {
69+
Node node = map.get(key);
70+
if (node != null) {
71+
updateFreq(node);
72+
return node.value;
73+
}
74+
return -1;
75+
}
76+
77+
public void put(int key, int value) {
78+
if (max <= 0) {
79+
return;
80+
}
81+
Node node = map.get(key);
82+
if (node != null) {
83+
//更新频率
84+
node.value = value;
85+
updateFreq(node);
86+
} else {
87+
cur++;
88+
if (cur > max) {
89+
deleteNode();
90+
cur--;
91+
}
92+
node = new Node(key, value, 1);
93+
map.put(key, node);
94+
addFreq(1, key);
95+
minFreq = 1;
96+
}
97+
}
98+
99+
private void deleteNode() {
100+
LinkedList<Integer> keys = freqMap.get(minFreq);
101+
if (keys != null && keys.size() > 0) {
102+
Integer deleteKey = keys.get(0);
103+
keys.remove(deleteKey);
104+
map.remove(deleteKey);
105+
}
106+
}
107+
108+
private void updateFreq(Node node) {
109+
removeFreq(node.freq, node.key);
110+
LinkedList<Integer> preKeyList = freqMap.get(node.freq);
111+
if (preKeyList != null && preKeyList.size() == 0 && minFreq == node.freq) {
112+
minFreq = node.freq + 1;
113+
}
114+
addFreq(++node.freq, node.key);
115+
}
116+
117+
private void removeFreq(int freq, int key) {
118+
LinkedList<Integer> keyList = freqMap.get(freq);
119+
if (keyList != null) {
120+
keyList.remove((Integer) key);
121+
}
122+
}
123+
124+
private void addFreq(int freq, int key) {
125+
LinkedList<Integer> keyList = freqMap.get(freq);
126+
if (keyList == null) {
127+
keyList = new LinkedList<>();
128+
freqMap.put(freq, keyList);
129+
}
130+
keyList.add(key);
131+
132+
}
133+
}
134+
135+
private static class Node {
136+
int key;
137+
int value;
138+
int freq;
139+
140+
public Node(int key, int value, int freq) {
141+
this.key = key;
142+
this.value = value;
143+
this.freq = freq;
144+
}
145+
}
146+
}

0 commit comments

Comments
 (0)