題目描述
設計LRU緩存結構,該結構在構造時確定大小,假設大小為K,並有如下兩個功能
- set(key, value):將記錄(key, value)插入該結構
- get(key):返回key對應的value值
[要求]
- set和get方法的時間復雜度為O(1)
- 某個key的set或get操作一旦發生,認為這個key的記錄成了最常使用的。
- 當緩存的大小超過K時,移除最不經常使用的記錄,即set或get最久遠的。
若opt=1,接下來兩個整數x, y,表示set(x, y)
若opt=2,接下來一個整數x,表示get(x),若x未出現過或已被移除,則返回-1
對於每個操作2,輸出一個答案
示例1
輸入
復制
[[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
輸出
復制
[1,-1]
說明
第一次操作后:最常使用的記錄為("1", 1)
第二次操作后:最常使用的記錄為("2", 2),("1", 1)變為最不常用的
第三次操作后:最常使用的記錄為("3", 2),("1", 1)還是最不常用的
第四次操作后:最常用的記錄為("1", 1),("2", 2)變為最不常用的
第五次操作后:大小超過了3,所以移除此時最不常使用的記錄("2", 2),加入記錄("4", 4),並且為最常使用的記錄,然后("3", 2)變為最不常使用的記錄
完整代碼
#include <unordered_map>
class Solution {
public:
// 維護一個有序單向鏈表,當有一個新的數據被訪問時,從鏈表頭部開始遍歷鏈表:
// 1 如果此數據之前已經在緩存中了,那么將其從原來的位置刪除,並將其插入到頭節點
// 2 如果此數據之前不在緩存中:
// 2.1 如果緩存未滿,則直接將此節點插入到頭節點
// 2.2 如果緩存已滿,則刪除鏈表尾節點,將新的數據插入到頭節點
// 復雜度為O(n)
// 使用散列表hashtable與雙向鏈表的組合
// 當要緩存某個數據的時候,先在鏈表中查找這個數據。如果沒有找到,則直接將數據放到鏈表的尾部;如果找到了,我們就把它移動到鏈表的尾部
// 當緩存空間不夠,需要淘汰一個數據的時候,我們就直接將鏈表頭部的結點刪除
// 復雜度為O(1)
unordered_map<int, int> map;
vector<int> cache;
vector<int> LRU(vector<vector<int> >& operators, int k) {
// write code here
vector<int> result;
for(int i = 0; i < operators.size(); i++){
if(operators[i][0] == 1){
set(operators[i][1], operators[i][2], k);
}else if(operators[i][0] == 2){
result.push_back(get(operators[i][1]));
}
}
return result;
}
void set(int key, int value, int k){
if(cache.size()== k){
map.erase(cache[0]);
cache.erase(cache.begin());
}
map[key] = value;
// 這個時候應該先查找cache中是否存在key,如果存在就把它刪除后放到尾部
for(int i = 0; i < cache.size(); i++){
if(cache[i] == key){
// 刪除
cache.erase(cache.begin() + i);
break;
}
}
// 放到尾部
cache.push_back(key);
}
int get(int key){
// 根本不存在或者已經被刪除了
if(map.find(key) == map.end()){
return -1;
}
// 這個時候應該先查找cache中是否存在key,如果存在就把它刪除后放到尾部
for(int i = 0; i < cache.size(); i++){
if(cache[i] == key){
// 刪除
cache.erase(cache.begin() + i);
// 放到尾部
cache.push_back(key);
break;
}
}
return map[key];
}
};