Leetcode 146. LRU缓存机制

这道题的思路就是 用一个链表list来纪录最近访问key的优先级,越靠近头部的就是优先访问的,越靠近尾部的就是越久没被访问的。
询问一个key,如果不存在就返回-1,如果存在的话,因为这个key最近被访问过了,所以要在list中更新,把这个元素放到开头。

int get(int key) {
		auto it = m.find(key);
		if (it == m.end()) return -1;
		L.splice(L.begin(), L, it->second);
		return it->second->second;
	}

在上面的操作中 如果要做到O(1)时间 要做到能通过key找到链表中的一个元素还要放到末尾,就需要用一个unordered_map来建立key和list迭代器的联系 而list里面可以存一个pair,也就是key对应的value,所以有了需要的数据结构

private:
	int cap;
	list<pair<int, int>> L;
	unordered_map<int, list<pair<int, int>>::iterator> m;

在插入的时候,如果在m中能找到这个key对应的iterator,说明key对应的value是存在的,而list中也需要更新,所以通过哈希表中key对应的iterator直接删除掉这个元素,然后无论是否key对应的value存在,都需要在list的开头加入<key,value>的pair
加入以后,需要更新哈希表中key对应的iterator指向list的头部
如果加入之后 list中的个数大于capacity,那么就需要删除least recently used的那个元素,也就是list末尾的那个元素,同时在map中将该key和iterator对应的项删除

void put(int key, int value) {
		auto it = m.find(key);
		if (it != m.end()) L.erase(it->second);
		L.push_front(make_pair(key, value));
		m[key] = L.begin();
		if (L.size() > cap)
		{
			auto it = L.rbegin();
			m.erase(it->first);
			L.pop_back();
		}

综上 全部的代码为

class LRUCache {
private:
	int cap;
	list<pair<int, int>> L;
	unordered_map<int, list<pair<int, int>>::iterator> m;
public:
	LRUCache(int capacity) {
		cap = capacity;
	}

	int get(int key) {
		auto it = m.find(key);
		if (it == m.end()) return -1;
		L.splice(L.begin(), L, it->second);
		return it->second->second;
	}
	void put(int key, int value) {
		auto it = m.find(key);
		if (it != m.end()) L.erase(it->second);
		L.push_front(make_pair(key, value));
		m[key] = L.begin();
		if (L.size() > cap)
		{
			auto it = L.rbegin();
			m.erase(it->first);
			L.pop_back();
		}

	}
};

今天从这道题里面学习到了特别多知识点
首先 map和unorderedmap的区别是
map是红黑树 是有序的 而unordered_map是哈希散列表 是无序的,可以做到O(1)复杂度的查询
其次 C++ stl的list的遍历的写法是

for(auto it=L.begin();it!=L.end();it++)

这里面it其实是list的迭代器
还有迭代器的写法 比如说如果要写

list<pair<int,int>>L;

的迭代器 那么迭代器的声明方式是

list<pair<int,int>>::iterator

也就是哈希散列表unordered_map里面要写的参数 这里用了一个哈希散列表
前面的key表示cache里面的用来寻找value的key 而散列表中对应的value是list<pair<int,int>>的迭代器 是为了将key和list的迭代器对应起来 就能在O(1)的时间找到list中需要被删除,插到头部的元素。
然后容器的末尾不需要用L.end()–什么的来访问 因为有反向迭代器,L.rbegin()就是容器的末尾
迭代器的splice用法 L.splice(位置,哪个容器,迭代器位置) 就可以把迭代器位置对应的那个东西放到对应容器的对应位置上,对应链表复杂度应该是O(1)。
如果是L.splice(位置,哪个容器,迭代器begin,迭代器end)应该就是把[begin,end)中的元素移动到对应容器的对应位置上,很好用 下次要记住。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值