LFU缓存结构设计

LFU缓存结构设计

题目描述

一个缓存结构需要实现如下功能。

  • set(key, value):将记录(key, value)插入该结构
  • get(key):返回key对应的value值

但是缓存结构中最多放K条记录,如果新的第K+1条记录要加入,就需要根据策略删掉一条记录,然后才能把新记录加入。这个策略为:在缓存结构的K条记录中,哪一个key从进入缓存结构的时刻开始,被调用set或者get的次数最少,就删掉这个key的记录;

如果调用次数最少的key有多个,上次调用发生最早的key被删除

这就是LFU缓存替换算法。实现这个结构,K作为参数给出

[要求]

set和get方法的时间复杂度为O(1)

输入描述:

第一行两个个整数N, K,表示操作数量以及缓存结构大小
接下来N行,第一行一个整数opt表示操作类型。
若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1

输出描述:

对于每个操作2,输出一个答案

示例1
输入
8 3
1 1 1
1 2 2
1 3 2
1 2 4
1 3 5
2 2
1 4 4
2 1
输出
4
-1
说明
在执行"1 2 4"后,"1 1 1"被删除。因此第二次询问的答案为-1
备注:

1 ⩽ K ⩽ N ⩽ 1 0 5 1 \leqslant K \leqslant N \leqslant 10^5 1KN105
− 2 ∗ 1 0 9 ⩽ x , y ⩽ 2 ∗ 1 0 9 -2 * 10^9 \leqslant x, y \leqslant 2 * 10^9 2109x,y2109


题解:

对每个 (key, value) 键值对,使用一个桶保存 key 被操作的次数,这里可以使用 multimap ,其可自动按照次数从小到大排序,定义为:multimap<int, pair<key, value> > freq_map;然后需要额外使用一个 unordered_map ,记录每个关键字对应的是哪个桶,定义为:unordered_map<int, multimap<int, pair<key, value> > > hash_map

  • set(key, value)

    首先在 hash_map 中查询是否存 key ,若存在,将其的出现频率+1,重新插入 freq_map 中,删除原有的 freq_map 记录;若不存在,则在 freq_map 中插入一个新的记录,在 hash_map 中记录新插入的位置,同时,若插入后 freq_map 的元素个数大于 k ,则要将以 freq_map.begin() 删除(此处 begin() 指的是 出现频率最小且最早的元素),同时在 hash_map 中删除对应的 key 。

  • get(key)

    同样的需要在 hash_map 中查询是否存在该 key ,不存在返回 -1,否则输出对应的值即可

代码:
#include <cstdio>
#include <unordered_map>
#include <map>

using namespace std;

template <class key_t, class value_t>
class LFU {
public:
    explicit LFU( size_t size ) : max_size( size ) {}
    
    value_t get( key_t key ) {
        auto iter = hash_map.find( key );
        if ( iter != hash_map.end() ) {
            auto newIter = freq_map.insert( { iter->second->first + 1, iter->second->second } );
            freq_map.erase( iter->second );
            hash_map[ key ] = newIter;
            return iter->second->second.second;
        } else {
            return -1;
        }
    }
    
    void set( key_t key, value_t value ) {
        auto iter = hash_map.find( key );
        if ( iter != hash_map.end() ) {
            auto newIter = freq_map.insert( { iter->second->first + 1, iter->second->second } );
            newIter->second.second = value;
            freq_map.erase( iter->second );
            hash_map[key] = newIter;
        } else {
            auto newIter = freq_map.insert( {1, { key, value } } );
            hash_map[key] = newIter;
            if ( freq_map.size() > max_size ) {
                hash_map.erase( freq_map.begin()->second.first );
                freq_map.erase( freq_map.begin() );
            }
        }
    }
private:
    using key_value_pair = pair< key_t, value_t >;
    using map_iterator = typename multimap< int, key_value_pair >::iterator;
    
    size_t max_size;
    multimap< int, key_value_pair > freq_map;
    unordered_map< key_t, map_iterator > hash_map;
};

int main(void) {
    int n, k;
    int op, key, val;
    scanf("%d%d", &n, &k);
    LFU<int, int> lfu( k );
    while ( n-- ) {
        scanf("%d%d", &op, &key);
        if ( op == 1 ) {
            scanf("%d", &val);
            lfu.set( key, val );
        } else {
            printf("%d\n", lfu.get( key ));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值