LeetCode146.148.155题解
146. LRU 缓存机制
题目描述
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]
解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
提示:
1 <= capacity <= 3000
0 <= key <= 3000
0 <= value <= 104
最多调用 3 * 104 次 get 和 put
C++代码
class DLinkedNode {
public:
int key;
int val;
DLinkedNode* pre;
DLinkedNode* next;
DLinkedNode() : key(0), val(0), pre(nullptr), next(nullptr) {}
DLinkedNode(int _key, int _val) : key(_key), val(_val), pre(nullptr), next(nullptr) {}
};
class LRUCache {
public:
LRUCache(int _capacity) {
size = 0;
capacity = _capacity;
head = new DLinkedNode(); // dummy head
tail = new DLinkedNode(); // dummy tail
head->next = tail;
tail->pre = head;
}
int get(int key) {
if (!cache.count(key)) {
return -1;
}
auto* node = cache[key];
moveToHead(node);
return node->val;
}
void put(int key, int value) {
if (cache.count(key)) {
// update the value
auto* node = cache[key];
// Since we are using pointer, no need to delete and re-add
node->val = value;
moveToHead(node);
} else {
if (size == capacity) {
auto tail = removeTail();
// Delete from cache, but not free
cache.erase(tail->key);
// Free the memory
delete tail;
size--;
}
auto* node = new DLinkedNode(key, value);
cache[key] = node;
addToHead(node);
size++;
}
}
void addToHead(DLinkedNode* node) {
head->next->pre = node;
node->next = head->next;
head->next = node;
node->pre = head;
}
void untie(DLinkedNode* node) {
node->pre->next = node->next;
node->next->pre = node->pre;
}
DLinkedNode* removeTail() {
auto node = tail->pre;
untie(node);
return node;
}
void moveToHead(DLinkedNode* node) {
untie(node);
addToHead(node);
}
private:
int size;
int capacity;
DLinkedNode* head;
DLinkedNode* tail;
unordered_map<int, DLinkedNode*> cache;
};//依旧看大佬题解,哈希表和双向链表的结合
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
148. 排序链表
题目描述
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
提示:
链表中节点的数目在范围 [0, 5 * 104] 内
-105 <= Node.val <= 105
C++代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode * sortList(ListNode * head)
{
return (head == NULL)? NULL: mergeSort(head);
}
private:
ListNode * findMid(ListNode * head)
{
ListNode * slow = head;
ListNode * fast = head;
ListNode * previous = NULL;
while (fast != NULL && fast->next != NULL)
{
previous = slow;
slow = slow->next;
fast = fast->next->next;
}
// split the list into two parts
previous->next = NULL;
return slow;
}
ListNode * mergeTwoLists(ListNode * l1, ListNode * l2)
{
if(l1 == NULL) return l2;
if(l2 == NULL) return l1;
if(l1->val < l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}else{
l2->next = mergeTwoLists(l1,l2->next);
return l2;
}
}
ListNode * mergeSort(ListNode * head)
{
if (head->next == NULL) return head;
ListNode * mid = findMid(head);
ListNode * l1 = mergeSort(head);
ListNode * l2 = mergeSort(mid);
return mergeTwoLists(l1, l2);
}
};//归并排序
155. 最小栈
题目描述
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
示例:
输入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
提示:
pop、top 和 getMin 操作总是在 非空栈 上调用。
C++代码
class MinStack {//用了两个栈进行存储
public:
stack<int> s;//数据栈
stack<int> min;//辅助栈
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
s.push(x);
if(min.empty()||x<=min.top())
{
min.push(x);
}
}
void pop() {
if(s.top()==min.top())
min.pop();
s.pop();
}
int top() {
return s.top();
}
int getMin() {
return min.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(x);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/