之前收藏了极客时间的算法训练营3期 共21课,计划每一课写博客来记录学习,主要形式为
方法类型1
题1
题解
题2
题解
方法类型2
题1
题解
……
题目大体来自leetcode 和 acwing
主要记录和理解代码,所以基本完全搬运了视频题解代码,
个人学习感受体现在大致思路的总结和注释上。
第一题
利用开关来整合相似的功能。
class Trie {
public:
Trie() {
root = new Node;
}
void insert(string word) {
find(word, true, false);
}
bool search(string word) {
return find(word, false, false);
}
bool startsWith(string prefix) {
return find(prefix, false, true);
}
private:
class Node {
public:
int count;
vector<Node*> child;
Node() {
count = 0;
child = vector<Node*>(26, nullptr);
}
};
Node* root;
bool find(string s, bool isInsert, bool isPrefix){
Node* curr = root;
for (char ch : s) {
if (curr->child[ch - 'a'] == nullptr) {
if (isInsert)
curr->child[ch - 'a'] = new Node();
else
return false;
}
curr = curr->child[ch - 'a'];
}
if (isInsert) curr->count++;
if (isPrefix) return true;
return curr->count > 0;
}
};
/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/
第二题
先把单词记录在字典树中,再根据前缀进行有选择的dfs
找过的单词会在字典树中删除,以加快速度。
class Solution {
public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
root = new Node;
for (string word : words) {
insert(word);
}
m = board.size();
n = board[0].size();
visit = vector<vector<bool>>(m, vector<bool>(n, false));
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
visit[i][j] = true;
dfs(board, i, j, root);
visit[i][j] = false;
}
return vector<string>(ans.begin(), ans.end());
}
private:
const int dx[4] = {-1, 0, 0, 1};
const int dy[4] = {0, -1, 1, 0};
class Node {
public:
int count;
unordered_map<char, Node*> child;
Node(){
count = 0;
}
};
Node* root;
int m, n;
vector<vector<bool>> visit;
string str;
unordered_set<string> ans;
void insert(string s) {
Node* curr = root;
for (char c : s) {
if (curr->child.find(c) == curr->child.end()) {
curr->child[c] = new Node();
}
curr = curr->child[c];
}
curr->count++;
}
void dfs(vector<vector<char>>& board, int x, int y, Node* curr) {
if (curr == nullptr) return;
char ch = board[x][y];
if (curr->child.find(ch) == curr->child.end()) return;
Node* next = curr->child[ch];
str.push_back(ch);
if (next->count > 0) ans.insert(str);
if (next->child.empty()){
curr->child.erase(ch);
delete next;
}
else{
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || nx >= m || ny >= n) continue;
if (visit[nx][ny]) continue;
visit[nx][ny] = true;
dfs(board, nx, ny, next);
visit[nx][ny] = false;
}
}
str.pop_back();
}
};
第三题
并查集,看根节点有几个即可。
class Solution {
public:
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size();
fa = vector<int>(n);
for (int i = 0; i < n; i++) fa[i] = i;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (isConnected[i][j]) unionSet(i, j);
int ans = 0;
for (int i = 0; i < n; i++)
if (fa[i] == i) ans++;
return ans;
}
private:
vector<int> fa;
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void unionSet(int x, int y) {
x = find(x);
y = find(y);
if (x != y) fa[x] = y;
}
};
第四题
利用并查集,查询每个点与外界的联系、
class Solution {
public:
void solve(vector<vector<char>>& board) {
m = board.size();
n = board[0].size();
fa = vector<int> (m * n + 1, 0);
for (int i = 0; i < m * n + 1; i++) {
fa[i] = i;
}
int out = m * n;
int dx[4] = {-1, 0, 0, 1};
int dy[4] = {0, -1, 1, 0};
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
if (board[i][j] == 'X') continue;
for (int i1 = 0; i1 < 4; i1++) {
int x = i;
int y = j;
int nx = x + dx[i1];
int ny = y + dy[i1];
if (nx < 0 || ny < 0 || nx >= m || ny >= n)
unionSet(toNum(x, y), out);
else {
if (board[nx][ny] == 'O')
unionSet(toNum(x, y), toNum(nx, ny));
}
}
}
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (board[i][j] == 'O' && find(toNum(i, j)) != find(out)) board[i][j] = 'X';
}
private:
vector<int> fa;
int m, n;
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unionSet (int x, int y) {
x = find(x);
y = find(y);
if (x != y) fa[x] = y;
}
int toNum(int i, int j) {
return i * n + j;
}
};
第五题
先按照利润大的卖,卖的时候考虑最后的时机,用并查集来维护相应日期前的最后可用日期。
#include <iostream>
#include <algorithm>
using namespace std;
pair<int, int> a[10001];
int n;
int fa[10001];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main() {
while(cin >> n) {
for (int i = 0; i < n; i++) {
cin >> a[i].first >> a[i].second;
}
sort(a, a + n);
for (int i = 0; i < 10001; i++) fa[i] = i;
int ans = 0;
for (int i = n - 1; i >= 0; i--) {
int profit = a[i].first;
int day = a[i].second;
int lastAvailableDay = find(day);
if (lastAvailableDay > 0) {
ans += profit;
fa[lastAvailableDay] = lastAvailableDay - 1;
}
}
cout << ans << endl;
}
}