146. LRU缓存
题目描述
请你设计并实现一个满足 LRU (最近最少使用) 缓存约束的数据结构。实现LRUCache
类:
- LRUCache(int capacity):以正整数作为容量 capacity ,初始化 LRU 缓存
- int get(int key) :如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value):如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过capacity ,则应该逐出最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/lru-cache
整体思路
- 这道题目的整体思路就是使用
哈希表 + 双向链表
来实现,哈希表中存储key->val
的映射,所有的节点按照双向链表来存储,方便进行插入删除。(当前可以使用c++提供的STL进行,也可以自己熟悉下这两者的工作方式,,虽然双向链表听起来可能很简单,但是真的动手去写,会有很多需要注意的地方,注意每个指针的指向,考虑全面) - get函数分析:
主要的函数流程如下,其中将节点置于队列尾部要分情况讨论,分别是该节点在head、tail或者中间位置。
- put函数分析
struct Node {
int val;
int key;
Node* last;
Node* next;
};
class LRUCache {
public:
LRUCache(int capacity) {
head = NULL;
tail = head;
size = 0;
this->capacity = capacity;
}
int get(int key) {
std::map<int, Node*>::iterator it = my_map.find(key);
if (it != my_map.end()) {
Node *tem_one = my_map[key];
if (tem_one == head) { // 访问的是head
head = tem_one->next;
tail = tem_one;
}
else if (tem_one != tail){ // 访问的不是tail,即为中间的
tem_one->last->next = tem_one->next;
tem_one->next->last = tem_one->last;
head->last = tem_one;
tem_one->next = head;
tail->next = tem_one;
tem_one->last = tail;
tail = tem_one;
}
return tem_one->val;
}
else {
return -1;
}
}
void put(int key, int value) {
std::map<int, Node*>::iterator it = my_map.find(key);
if (it != my_map.end()) { // 存在,置于队尾
Node *tem_one = my_map[key];
my_map[key]->val = value;
if (tem_one == head) { // 访问的是head
head = tem_one->next;
tail = tem_one;
}
else if (tem_one != tail){ // 访问的不是tail,即为中间的
tem_one->last->next = tem_one->next;
tem_one->next->last = tem_one->last;
head->last = tem_one;
tem_one->next = head;
tail->next = tem_one;
tem_one->last = tail;
tail = tem_one;
}
}
else { // 不存在
if (size < capacity) { // 还没有满
Node* new_one = new Node;
new_one->val = value;
new_one->key = key;
my_map[key] = new_one;
size++;
if (head == NULL) { // 还没有节点存在
head = new_one;
tail = head;
new_one->last = new_one;
new_one->next = new_one;
}
else { // 已经存在一个节点
new_one->last = tail;
new_one->next = head;
tail->next = new_one;
head->last = new_one;
tail = new_one;
}
}
else { // 满了,删掉head,并将新的添加到队尾
Node *tem_one = head;
my_map.erase(tem_one->key);
tem_one->key = key;
tem_one->val = value;
my_map[key] = tem_one;
head = tem_one->next;
tail = tem_one;
}
}
}
private:
Node* head;
Node* tail;
int size;
int capacity;
map<int, Node*> my_map;
};
103. 二叉树的锯齿形层序遍历
题目描述
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
- 整体思想比较简单,每次遍历时,将当前层的节点按照顺序保存下来,用来进行下一次遍历。同时将每层的节点val保存为一个vector,用来记录结果。
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<TreeNode*> left;
vector<TreeNode*> right;
vector<vector<int>> res;
if (root == NULL) {return res;}
res.push_back(vector<int>(1, root->val)); // push the first
bool left_first = true;
left.push_back(root);
while (left.size() != 0 || right.size() != 0) {
vector<int> tem_res; // 存储这一层的结果
if (left_first) { // 从左向右
int n = left.size();
for (int i = 0; i < n; ++i) {
TreeNode* tem = left.back();
left.pop_back();
if (tem->right != NULL) {
tem_res.push_back(tem->right->val);
right.insert(right.begin(), tem->right);
}
if (tem->left != NULL) {
tem_res.push_back(tem->left->val);
right.insert(right.begin(), tem->left);
}
}
}
else { // 从右向左
int n = right.size();
for (int i = 0; i < n; ++i) {
TreeNode* tem = right[0];
right.erase(right.begin());
if (tem->left != NULL) {
tem_res.push_back(tem->left->val);
left.push_back(tem->left);
}
if (tem->right != NULL) {
tem_res.push_back(tem->right->val);
left.push_back(tem->right);
}
}
}
if (!tem_res.empty()) {
res.push_back(tem_res);
}
left_first = !left_first;
}
return res;
}
};