之前收藏了极客时间的算法训练营3期 共10周,计划每周内容分3p博客来记录学习,主要形式为
方法类型1
题1
题解
题2
题解
方法类型2
题1
题解
……
题目大体来自leetcode 和 acwing
主要记录和理解代码,所以基本完全搬运了视频题解代码,
个人学习感受体现在大致思路的总结和注释上。
一、哈希表
1.两数之和
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for(int i = 0; i < nums.size(); i++){
//哈希表让直接搜索对应数字的复杂度降为O(1)
if(h.find(target - nums[i]) != h.end()){
return {h[target-nums[i]], i};
}
h[nums[i]]= i;
}
return {0};
}
private:
unordered_map<int, int> h;
};
2.模拟行走机器人
方向数组
障碍的处理中使用了哈希表。由于不能直接用pair哈希,故设计了到int的哈希、
class Solution {
public:
int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {
int ans = 0;
for(const vector<int>& ob : obstacles) {
h.insert(cal({ob[0], ob[1]}));
}
int x = 0, y = 0;
int dir = 0; //N = 0,E = 1, S = 2, W = 3;
//方向对应的移动指令。
const int dx[4] = {0, 1, 0 ,-1};
const int dy[4] = {1, 0, -1, 0};
for (int command : commands) {
//注意转向,取余来解决循环;
if (command == -1){
dir = (dir + 1) % 4;
}else if (command == -2){
dir = (dir + 3) % 4;
}else{
for (int i = 0; i < command; i++){
int nx = 0,ny = 0;
nx = x + dx[dir];
ny = y + dy[dir];
//查询障碍
if(h.find(cal({nx, ny})) != h.end()) break;
x = nx;
y = ny;
}
}
ans = max(ans, x * x + y * y);
}
return ans;
}
private:
long long cal (pair<int, int> x) {
return (x.first + 3 * 1e4) * 6 * 1e4 + x.second + 3 * 1e4;
}
unordered_set<long long > h;
};
3.字母异位词分组
把字母排序,存在hash_map 里面,map第二项存答案数组。注意hash_Map的遍历
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
for (string& s : strs) {
string copy = s;//排序之后会丢失原始数据
sort(copy.begin(), copy.end());
groups[copy].push_back(s);
}
vector<vector<string>> ans;
//接下来注意hash——map的遍历方式
for (const pair<string, vector<string>>& group : groups) {
ans.push_back(group.second);//把哈希表中存的数组返回
}
return ans;
}
private:
unordered_map<string , vector<string>> groups;
};
在循环中判定每一个长度和答案相等的串是否可行
判定可行使用哈希表的统计功能,并涉及到2个hash_map的比较问题。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
int total = 0;
for (string& word : words) {
total += word.length();
wordsMap[word] ++;//建立哈希表,匹配子串。
}
vector<int> ans;
//对于每一个可能的位置判断
for (int i = 0; i + total <= s.length(); i++){
if (valid(s.substr(i, total), words)){
ans.push_back(i);
}
}
return ans;
}
private:
unordered_map<string, int> wordsMap;
//分组,建立哈希表,并对比哈希表。
bool valid (string str, vector<string>& words) {
int k = words[0].length();
unordered_map<string, int> splitwords;
for (int i = 0; i < str.length(); i += k) {
splitwords[str.substr(i, k)] ++;//同建立哈希表
}
return equals_map(splitwords, wordsMap);
}
bool equals_map (unordered_map<string, int>& a, unordered_map<string, int>& b) {
//因为数量已经一样了,所以不用翻来覆去的判定两次。
for (const pair<string, int>& key_and_value : a) {
const string& key = key_and_value.first;
const int value = key_and_value.second;
if(b.find(key) == b.end() || b[key] != value) return false;
}
return true;
}
};
5.. LRU 缓存
最近最少使用,每次使用就提到最前。
题意要求get 和put 在O(1)内完成,故用hash_map来维护k
class LRUCache {
public:
LRUCache(int capacity) {
capa = capacity;
head = new Node();
tail = new Node();
head->next = tail;
tail->pre = head;
}
int get(int key) {
if (h.find(key) == h.end()) return -1;
Node* node = h[key];//把结点提到顶部
remove(node);
insert(head, node);
return node->val;
}
void put(int key, int value) {
if (h.find(key) == h.end()) {
Node* node = new Node();
node->val = value;
node->key = key;
h[key] = node;
insert(head,node);
if(h.size() > capa){
h.erase(tail->pre->key);//删去底部
remove(tail->pre);
}
}else{//更新一下数据放到顶部
Node* node = h[key];
node->val = value;
remove(node);
insert(head, node);
}
}
private:
int capa;
struct Node {
int key;
int val;
Node* pre;
Node* next;
};
unordered_map<int, Node*> h;
Node* head;
Node* tail;
void insert (Node* p, Node* node) {
p->next->pre = node;
node->next = p->next;
node->pre = p;
p->next = node;
}
void remove (Node* p) {
p->next->pre = p->pre;
p->pre->next = p->next;
}
};
/**
* 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);
*/
ey值