哈希表
两数之和
1.问题描述
给定一个整数数组,已知有且只有两个数的和等于给定值,求这两个数的位置。
2.输入输出
- Input:nums = [2, 7, 11, 15],target = 9
- Output:[0, 1]
3.算法分析
利用哈希表存储遍历过的值以及它们的位置,每次遍历到位置i的时候,查找哈希表里是否存在target-nums[i],若存在,说明这两个值得和为target。
4.编程实现
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash;
vector<int> ans;
for (int i = 0; i < nums.size(); i++) {
int num = nums[i];
auto pos = hash.find(target - num);
if (pos == hash.end()) {
hash[num] = i;
} else {
ans.push_back(pos->second);
ans.push_back(i);
break;
}
}
return ans;
}
};
int main() {
Solution sol;
vector<int> nums;
int value, target;
getchar();
while (cin >> value) {
nums.push_back(value);
if (cin.get() == ']') break;
}
cin >> target;
vector<int> ans = sol.twoSum(nums, target);
cout << ans[0] << " " << ans[1] << endl;
return 0;
}
并查集和LRU等复合数据结构
LRU缓存机制
leetcode 146:https://leetcode-cn.com/problems/lru-cache/
NC93:https://www.nowcoder.com/practice/e3769a5f49894d49b871c09cadd13a61?tpId=188
1.问题描述
设计一个固定大小的,最少最近使用缓存(Least recently used cache,LRU)。每次将信息插入未满的缓存的时候,以及更新或查找一个缓存内存在的信息的时候,将该信息标为最近使用。在缓存未满的情况下将一个新信息插入的时候,需要移除最旧的信息,插入新的信息,并将该信息标为最近使用。
2.输入输出
LRUCache lRUCache = new LRUCache(2); // 容量为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
3.算法分析
【这类题通常采用unordered_map或map辅助记录,从而加速寻址;再配上vector或者list进行数据储存,从而加速连续选址或删除值】
- 采用链表list<pair<int, int>>来储存信息的key和value,链表的链接顺序即为最近使用的新旧顺序,最新的信息在链表头节点。
- 同时使用一个嵌套了链表的迭代器的unordered_map<int, list<pair<int, int>>::iterator>进行快速搜索,存迭代器的原因是方便调用链表的splice函数来直接更新查找成功(cash hit)的信息,即把迭代器对应的节点移动为链表的头节点。
4.编程实现
#include <iostream>
#include <vector>
#include <numeric>
#include <list>
#include <unordered_map>
using namespace std;
class LRUCache {
// 快速搜索,存迭代器的原因是方便调用链表的splice函数来直接更新查找成功(cash hit)的信息,即把迭代器对应的节点移动为链表的头节点。
unordered_map<int, list<pair<int, int>>::iterator> hash;
list<pair<int, int>> cache; // 储存信息的key和value,链表的链接顺序即为最近使用的新旧顺序,最新的信息在链表头节点
int size;
public:
LRUCache(int capacity) :size(capacity){} // 以正整数作为容量capacity初始化LRU缓存
int get(int key) { // 如果关键字key存在于缓存中,则返回关键字的值,否则返回-1
auto it = hash.find(key);
if (it == hash.end()) return -1;
cache.splice(cache.begin(), cache, it->second);
return it->second->second;
}
void put(int key, int value) { // 如果关键字已经存在,则变更其数据值;关键字不存在,则插入该组[关键字-值]
// 当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据留出空间。
auto it = hash.find(key);
if (it != hash.end()) {
it->second->second = value;
return cache.splice(cache.begin(), cache, it->second); // 将它移到表头
}
cache.insert(cache.begin(), make_pair(key, value)); // 插入缓存头中
hash[key] = cache.begin();
if (cache.size() > size) {
hash.erase(cache.back().first);
cache.pop_back();
}
}
};
int main() {
LRUCache *lRUCache = new LRUCache(2); // 容量为2
lRUCache->put(1, 1); // 缓存是 {1=1}
lRUCache->put(2, 2); // 缓存是 {1=1, 2=2}
cout << lRUCache->get(1) << endl; // 返回 1
lRUCache->put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
cout << lRUCache->get(2) << endl; // 返回 -1 (未找到)
lRUCache->put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
cout << lRUCache->get(1) << endl; // 返回 -1 (未找到)
cout << lRUCache->get(3) << endl; // 返回 3
cout << lRUCache->get(4) << endl; // 返回 4
return 0;
}
栈
有效括号
Leetcode:https://leetcode-cn.com/problems/valid-parentheses/
1.问题描述
给定一个只由左右原括号、花括号和方括号组成的字符串,求这个字符串是否合法。合法的定义是每一类型的左括号都有一个右括号一一对应,且括号内的字符串也满足此要求。
2.输入输出
- Input:“{[]}()”
- Output:true
3.算法分析
括号匹配——典型栈问题,从左到右遍历,每当遇到左括号便放入栈内,遇到右括号则判断其和栈顶的括号是否是统一类型,是则从栈内取出左括号,否则说明字符串不合法。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
4.编程实现
#include <iostream>
#include <stack>
using namespace std;
class Solution {
public:
bool isValid(string s) {
stack<char> parsed;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '{' || s[i] == '(' || s[i] == '[') {
parsed.push(s[i]);
} else {
if (parsed.empty()) return false;
char c = parsed.top();
if ((s[i] == '}' && c == '{') || (s[i] == ')' && c == '(') || (s[i] == ']' && c == '[')) {
parsed.pop();
} else {
return false;
}
}
}
return parsed.empty();
}
};
int main() {
Solution sol;
string s;
cin >> s;
cout << sol.isValid(s) << endl;
return 0;
}