LeetCode LFU缓存(hash表)

题目要求 设计并实现最不经常使用(LFU)缓存的数据结构。它应该支持以下操作:get 和 put。

get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。
put(key, value) - 如果键不存在,请设置或插入值。当缓存达到其容量时,它应该在插入新项目之前,使最不经常使用的项目无效。
	在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,最近最少使用的键将被去除。

进阶:
你是否可以在 O(1) 时间复杂度内执行两项操作?
示例:

LFUCache cache = new LFUCache( 2 /* capacity (缓存容量) */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回 1
cache.put(3, 3);    // 去除 key 2
cache.get(2);       // 返回 -1 (未找到key 2)
cache.get(3);       // 返回 3
cache.put(4, 4);    // 去除 key 1
cache.get(1);       // 返回 -1 (未找到 key 1)
cache.get(3);       // 返回 3
cache.get(4);       // 返回 4

设计思路:请先翻阅 缓存机制 LRU 和 LFU
算法实现:

class LFUCache {
private:
	int maxSize, minFreq;//代表的使用次数的最小值(频率最小
	unordered_map<int, pair<int, int>> dataMap;//分别代表key,val,使用次数
	unordered_map<int, list<int>> freqMap;//分别代表使用次数cnt,使用次数为cnt的key的集合
	unordered_map<int, list<int>::iterator> keyIter;//分别代表key,以及在freqMap中的迭代器
public:
	LFUCache(int capacity) {
		maxSize = capacity;
	}
	int get(int key) {
		if (dataMap.count(key) == 0) {
			return -1;
		}
		//get了一次,使用次数自增
		freqMap[dataMap[key].second].erase(keyIter[key]);//同keyIter删除freqMap中key对应的位置
		dataMap[key].second += 1;//使用次数自增
		freqMap[dataMap[key].second].push_back(key);//依据现在使用的次数重新写入freqMap中使用次数为dataMap[key].second的list端的尾部
		keyIter[key] = --freqMap[dataMap[key].second].end();//现在key在freqMap中使用次数为dataMap[key].second的list端的尾端
		if (freqMap[minFreq].size() == 0) {//更新当前使用次数最小值
			++minFreq;
		}
		return dataMap[key].first;//返回key对应的value
	}

	void put(int key, int value) {
		if (maxSize <= 0) {
			return;
		}
		//如果之前就在dataMap中,则调用put后需要更新key使用的次数,并且修改key对应的keyIter
		if (get(key) != -1) {
			dataMap[key].first = value;//更新value
			return;
		}
		//判断dataMap大小是否超过最大值
		if (dataMap.size() >= maxSize) {
			//freqMap[minFreq].front()为当前需要移除的key
			//minFreq表示使用次数最少(主),freqMap[minFreq]的前端代表最近最少使用(副)(类似LRU条件)
			dataMap.erase(freqMap[minFreq].front());
			keyIter.erase(freqMap[minFreq].front());
			freqMap[minFreq].pop_front();
		}
		dataMap[key] = { value, 1 };
		freqMap[1].push_back(key);//将key插入使用次数只有一次的list尾端
		keyIter[key] = --freqMap[1].end();//确定key插入freqMap中的迭代器
		minFreq = 1;//当前使用次数最少的是1,即刚刚插入的key只用了一次
	}
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/88909255
今日推荐