s0146
This commit is contained in:
parent
a99d75b44c
commit
bef47e10bf
50
include/s0146_lru_cache.hpp
Normal file
50
include/s0146_lru_cache.hpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef S0146_LRU_CACHE_HPP
|
||||||
|
#define S0146_LRU_CACHE_HPP
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class LRUCache {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Least Recently Used Cache
|
||||||
|
*
|
||||||
|
* 这是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰
|
||||||
|
*
|
||||||
|
* @param capacity 容量,这是一个正整数
|
||||||
|
*/
|
||||||
|
LRUCache(int capacity);
|
||||||
|
/**
|
||||||
|
* @brief 读取数据
|
||||||
|
*
|
||||||
|
* @param key 数据对应的键值
|
||||||
|
* @return 数据的值
|
||||||
|
*/
|
||||||
|
int get(int key);
|
||||||
|
/**
|
||||||
|
* @brief 放入对应的数据
|
||||||
|
*
|
||||||
|
* @param key 数据对应的键值
|
||||||
|
* @param value 数据对应的值
|
||||||
|
*/
|
||||||
|
void put(int key, int value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CacheNode {
|
||||||
|
int key;
|
||||||
|
int value;
|
||||||
|
CacheNode *next;
|
||||||
|
CacheNode *prev;
|
||||||
|
CacheNode(int key, int value)
|
||||||
|
: key(key), value(value), next(nullptr), prev(nullptr){};
|
||||||
|
CacheNode(int key, int value, CacheNode *next, CacheNode *prev)
|
||||||
|
: key(key), value(value), next(next), prev(prev){};
|
||||||
|
};
|
||||||
|
CacheNode *head;
|
||||||
|
CacheNode *tail;
|
||||||
|
int capacity;
|
||||||
|
std::unordered_map<int, CacheNode *> map; // 键值是 key,值是该节点的指针
|
||||||
|
void moveToHead(CacheNode *node); // 将节点移动到头部
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -77,3 +77,4 @@
|
|||||||
- [单调队列](./stack_and_queue.md)
|
- [单调队列](./stack_and_queue.md)
|
||||||
- [二叉树遍历](./btree_iter.md)
|
- [二叉树遍历](./btree_iter.md)
|
||||||
- [合并两个有序链表](./merge_two_sorted_linked_lists.md)
|
- [合并两个有序链表](./merge_two_sorted_linked_lists.md)
|
||||||
|
- [LRU](./lru_cache.md)
|
||||||
|
128
notes/src/lru_cache.md
Normal file
128
notes/src/lru_cache.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# LRU
|
||||||
|
|
||||||
|
[Leetcode 146. LRU Cache](https://leetcode.cn/problems/lru-cache/description/)
|
||||||
|
|
||||||
|
Header:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#ifndef S0146_LRU_CACHE_HPP
|
||||||
|
#define S0146_LRU_CACHE_HPP
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class LRUCache {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Least Recently Used Cache
|
||||||
|
*
|
||||||
|
* 这是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰
|
||||||
|
*
|
||||||
|
* @param capacity 容量,这是一个正整数
|
||||||
|
*/
|
||||||
|
LRUCache(int capacity);
|
||||||
|
/**
|
||||||
|
* @brief 读取数据
|
||||||
|
*
|
||||||
|
* @param key 数据对应的键值
|
||||||
|
* @return 数据的值
|
||||||
|
*/
|
||||||
|
int get(int key);
|
||||||
|
/**
|
||||||
|
* @brief 放入对应的数据
|
||||||
|
*
|
||||||
|
* @param key 数据对应的键值
|
||||||
|
* @param value 数据对应的值
|
||||||
|
*/
|
||||||
|
void put(int key, int value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CacheNode {
|
||||||
|
int key;
|
||||||
|
int value;
|
||||||
|
CacheNode *next;
|
||||||
|
CacheNode *prev;
|
||||||
|
CacheNode(int key, int value)
|
||||||
|
: key(key), value(value), next(nullptr), prev(nullptr){};
|
||||||
|
CacheNode(int key, int value, CacheNode *next, CacheNode *prev)
|
||||||
|
: key(key), value(value), next(next), prev(prev){};
|
||||||
|
};
|
||||||
|
CacheNode *head;
|
||||||
|
CacheNode *tail;
|
||||||
|
int capacity;
|
||||||
|
std::unordered_map<int, CacheNode *> map; // 键值是 key,值是该节点的指针
|
||||||
|
void moveToHead(CacheNode *node); // 将节点移动到头部
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
Source:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "s0146_lru_cache.hpp"
|
||||||
|
|
||||||
|
void LRUCache::moveToHead(CacheNode *node) {
|
||||||
|
// 如果是头部节点
|
||||||
|
if (node == head) return;
|
||||||
|
// 如果不是头部节点,但是是尾部节点
|
||||||
|
if (node == tail) tail = node->prev;
|
||||||
|
// 处理该节点的前后两个节点的指针
|
||||||
|
if (node->prev) node->prev->next = node->next;
|
||||||
|
if (node->next) node->next->prev = node->prev;
|
||||||
|
// 将该节点移动到头部
|
||||||
|
node->prev = nullptr;
|
||||||
|
node->next = head;
|
||||||
|
// 处理头部节点
|
||||||
|
head->prev = node;
|
||||||
|
head = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRUCache::LRUCache(int capacity) {
|
||||||
|
this->capacity = capacity;
|
||||||
|
head = nullptr;
|
||||||
|
tail = nullptr;
|
||||||
|
map = std::unordered_map<int, CacheNode *>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int LRUCache::get(int key) {
|
||||||
|
if (map.size() == 0) return -1;
|
||||||
|
if (map.count(key) == 0) return -1;
|
||||||
|
moveToHead(map[key]);
|
||||||
|
return map[key]->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRUCache::put(int key, int value) {
|
||||||
|
// 如果 key 已存在,则更新 value ,并将这个节点移动到头部
|
||||||
|
if (map.count(key) == 1) {
|
||||||
|
map[key]->value = value;
|
||||||
|
moveToHead(map[key]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 否则创建该节点
|
||||||
|
CacheNode *newNode = (CacheNode *)malloc(sizeof(CacheNode));
|
||||||
|
newNode->value = value;
|
||||||
|
newNode->key = key;
|
||||||
|
newNode->next = head;
|
||||||
|
newNode->prev = nullptr;
|
||||||
|
// 处理头部节点
|
||||||
|
if (head) head->prev = newNode;
|
||||||
|
head = newNode;
|
||||||
|
// 处理尾部节点
|
||||||
|
if (map.size() == 0) tail = newNode;
|
||||||
|
// 更新哈希表
|
||||||
|
map[key] = newNode;
|
||||||
|
// 如果容量已满
|
||||||
|
if (map.size() > capacity) {
|
||||||
|
// 更新尾部节点
|
||||||
|
CacheNode *node = tail;
|
||||||
|
if (tail->prev) {
|
||||||
|
tail->prev->next = nullptr;
|
||||||
|
tail = tail->prev;
|
||||||
|
}
|
||||||
|
// 移除该节点
|
||||||
|
map.erase(node->key);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
65
src/s0146_lru_cache.cpp
Normal file
65
src/s0146_lru_cache.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include "s0146_lru_cache.hpp"
|
||||||
|
|
||||||
|
void LRUCache::moveToHead(CacheNode *node) {
|
||||||
|
// 如果是头部节点
|
||||||
|
if (node == head) return;
|
||||||
|
// 如果不是头部节点,但是是尾部节点
|
||||||
|
if (node == tail) tail = node->prev;
|
||||||
|
// 处理该节点的前后两个节点的指针
|
||||||
|
if (node->prev) node->prev->next = node->next;
|
||||||
|
if (node->next) node->next->prev = node->prev;
|
||||||
|
// 将该节点移动到头部
|
||||||
|
node->prev = nullptr;
|
||||||
|
node->next = head;
|
||||||
|
// 处理头部节点
|
||||||
|
head->prev = node;
|
||||||
|
head = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRUCache::LRUCache(int capacity) {
|
||||||
|
this->capacity = capacity;
|
||||||
|
head = nullptr;
|
||||||
|
tail = nullptr;
|
||||||
|
map = std::unordered_map<int, CacheNode *>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int LRUCache::get(int key) {
|
||||||
|
if (map.size() == 0) return -1;
|
||||||
|
if (map.count(key) == 0) return -1;
|
||||||
|
moveToHead(map[key]);
|
||||||
|
return map[key]->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LRUCache::put(int key, int value) {
|
||||||
|
// 如果 key 已存在,则更新 value ,并将这个节点移动到头部
|
||||||
|
if (map.count(key) == 1) {
|
||||||
|
map[key]->value = value;
|
||||||
|
moveToHead(map[key]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 否则创建该节点
|
||||||
|
CacheNode *newNode = (CacheNode *)malloc(sizeof(CacheNode));
|
||||||
|
newNode->value = value;
|
||||||
|
newNode->key = key;
|
||||||
|
newNode->next = head;
|
||||||
|
newNode->prev = nullptr;
|
||||||
|
// 处理头部节点
|
||||||
|
if (head) head->prev = newNode;
|
||||||
|
head = newNode;
|
||||||
|
// 处理尾部节点
|
||||||
|
if (map.size() == 0) tail = newNode;
|
||||||
|
// 更新哈希表
|
||||||
|
map[key] = newNode;
|
||||||
|
// 如果容量已满
|
||||||
|
if (map.size() > capacity) {
|
||||||
|
// 更新尾部节点
|
||||||
|
CacheNode *node = tail;
|
||||||
|
if (tail->prev) {
|
||||||
|
tail->prev->next = nullptr;
|
||||||
|
tail = tail->prev;
|
||||||
|
}
|
||||||
|
// 移除该节点
|
||||||
|
map.erase(node->key);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
}
|
26
tests/s0146_lru_cache.cpp
Normal file
26
tests/s0146_lru_cache.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "s0146_lru_cache.hpp"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
TEST(Problem146, Case1) {
|
||||||
|
LRUCache *lru = new LRUCache(2);
|
||||||
|
lru->put(1, 1);
|
||||||
|
lru->put(2, 2);
|
||||||
|
EXPECT_EQ(lru->get(1), 1);
|
||||||
|
lru->put(3, 3);
|
||||||
|
EXPECT_EQ(lru->get(2), -1);
|
||||||
|
lru->put(4, 4);
|
||||||
|
EXPECT_EQ(lru->get(1), -1);
|
||||||
|
EXPECT_EQ(lru->get(3), 3);
|
||||||
|
EXPECT_EQ(lru->get(4), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Problem146, Case2) {
|
||||||
|
LRUCache *lru = new LRUCache(2);
|
||||||
|
lru->put(2, 1);
|
||||||
|
lru->put(1, 1);
|
||||||
|
lru->put(2, 3);
|
||||||
|
lru->put(4, 1);
|
||||||
|
EXPECT_EQ(lru->get(1), -1);
|
||||||
|
EXPECT_EQ(lru->get(2), 3);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user