题解 | #设计LRU缓存结构#

设计LRU缓存结构

https://www.nowcoder.com/practice/5dfded165916435d9defb053c63f1e84

基本思想

需要O(1)时间的插入删除,必须要一个map,此外需要判断时间,那么还需要一个双链表。如果自己实现双链表,会很麻烦,可以直接使用list。

需要设置一个节点类型,Node{k,v},list存储Node*指针。注意必须要有k,方便后续删除最后一个节点的时候,根据k去删除map。

接下来就是map了,注意这里的value需要指向list中的元素的位置,因此不能是Node*,这样会没法直接定位到链表的节点,需要 list<Node*>::iterator 存储一个迭代器,这样*解引用就可以指向那个被访问的list节点了,方便插入和删除。

核心结构如下

struct Node {
	int k, v;
};
map<int, list<Node*>::iterator> kv;
list<Node*> li;

代码演示

代码很详细,按照我的注释逻辑,手动推演一下,很容易明白。

struct Node {
	int k, v;
};

struct Solution {
	map<int, list<Node*>::iterator> kv; // O1查找
	list<Node*> li;   // 区分前后,begin() 最新,
	int capacity ; 

	Solution(int c): capacity(c){

	}
	~Solution() {
		for (Node* pn : li) {
			delete pn;
		}
	}
	void set(int k, int v) {
		// 如果存在 更新即可
		if (kv.count(k)) {
			auto node = kv[k];
			(*node)->v = v; // 把迭代器解引用,然后取出v
			get(k); // update
		}
		else {
			// 否则插入
			Node* cur=new Node{ k,v };
			li.push_front(cur); //前面是最新的
			kv[k] = li.begin(); //map存储的是迭代器
			

			if (kv.size() > capacity) {
				// 删除多余的
				Node* del = li.back();
				kv.erase(del->k); // map和list中同时删除
				li.pop_back();
				delete del; //记得别内存泄露了
			}

		}
	}

	int get(int k) {
		int ret = -1;
		// 如果存在
		if (kv.count(k)) {
			auto cur = kv[k];
			ret = (*cur)->v;
			// 更新位置
			li.push_front(*cur); // 这两步别反了,先把Node*插入头,再反过头删除原来的迭代器位置
			li.erase(cur); 
			kv[k] = li.begin(); // 重新指向新的迭代器
			return ret;
		}
		else {
			//否则 返回-1
			return ret;
		}
	}

};

全部评论

相关推荐

11-08 17:36
诺瓦科技_HR
点赞 评论 收藏
分享
头像
11-18 16:08
福州大学 Java
影流之主:干10年不被裁,我就能拿别人一年的钱了,日子有盼头了
点赞 评论 收藏
分享
点赞 1 评论
分享
牛客网
牛客企业服务