Leetcode hot100(day 5)
实现trie(前缀树)
做法:acwing基础课相同,这里由于是在类里面,不能直接创建一个节点在类内,所以可以用this
class Trie {
public:
vector<Trie*>children;
bool isend;
//Trie root;
Trie* searchprefix(string prefix)
{
Trie* node=this;
for(char ch:prefix)
{
ch=ch-'a';
if(node->children[ch]==nullptr)return nullptr;
node=node->children[ch];
}
return node;
}
Trie():children(26),isend(false) {
}
void insert(string word) {
Trie* node=this;
for(char ch:word)
{
ch=ch-'a';
if(node->children[ch]==nullptr)node->children[ch]=new Trie();
node=node->children[ch];
}
node->isend=true;
}
bool search(string word) {
Trie* node=this->searchprefix(word);
return node!=nullptr&&node->isend;
}
bool startsWith(string prefix) {
return this->searchprefix(prefix)!=nullptr;
}
};
全排列
做法:非常经典的dfs回溯,刚好练练手
class Solution {
public:
vector<vector<int>> v;
void dfs(vector<int>&vec,int k,vector<int>& nums,vector<bool>&st)
{
if(k==nums.size())
{
v.emplace_back(vec);
return;
}
for(int i=0;i<nums.size();i++)
{
if(st[i]==false)
{
vec.emplace_back(nums[i]);
st[i]=true;
dfs(vec,k+1,nums,st);
vec.pop_back();
st[i]=false;
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
int sz=nums.size();
vector<bool> st(sz,false);
vector<int> vec;
dfs(vec,0,nums,st);
return v;
}
};
子集
做法一:迭代法,如果一共有n个元素的集合,那么包括空集,一共有2^n种状态,恰好对应n位2进制的个数,所以我们遍历二进制即可
class Solution {
public:
vector<int> t;
vector<vector<int>> ans;
vector<vector<int>> subsets(vector<int>& nums) {
int n=nums.size();
for(int mask=0;mask<(1<<n);mask++)
{
t.clear();
for(int i=0;i<n;i++)
{
if(mask&(1<<i))t.push_back(nums[i]);
}
ans.push_back(t);
}
return ans;
}
};
做法二:递归法,递归要设置出口,所以还是和之前一样,在n==size的时候出去,但这时候因为要选择子序列,所以要有选择和不选择两种递归路线
class Solution {
public:
vector<int> t;
vector<vector<int>> ans;
void dfs(int cur,vector<int>& nums)
{
if(cur==nums.size())
{
ans.push_back(t);
return;
}
t.push_back(nums[cur]);
dfs(cur+1,nums);
t.pop_back();
dfs(cur+1,nums);
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(0,nums);
return ans;
}
};
电话号码的字母组合
做法:递归,和前面没什么区别,只是复杂了一点点而已
class Solution {
public:
vector<string> ans;
string path;
unordered_map<char, string> mp{
{'2', "abc"},
{'3', "def"},
{'4', "ghi"},
{'5', "jkl"},
{'6', "mno"},
{'7', "pqrs"},
{'8', "tuv"},
{'9', "wxyz"}
};
void dfs(string digits,int cur)
{
if(cur==digits.size())
{
ans.push_back(path);
return;
}
string letter=mp[digits[cur]];
for(int i=0;i<letter.size();i++)
{
path.push_back(letter[i]);
dfs(digits,cur+1);
path.pop_back();
}
}
vector<string> letterCombinations(string digits) {
if(digits.empty())return {};
dfs(digits,0);
return ans;
}
};
组合总和
做法:回溯秒了。本来想用sort看能不能再剪枝,但最后反而时间更多,所以就采用正常的剪枝了
class Solution {
public:
vector<vector<int>> ans;
void dfs(vector<int>& nums,int k,int target,vector<int>& vec)
{
if(k==nums.size())return;
if(target==0){ans.emplace_back(vec);return;}
dfs(nums,k+1,target,vec);
if(target-nums[k]>=0)
{
vec.emplace_back(nums[k]);
dfs(nums,k,target-nums[k],vec);
vec.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<int> vec;
dfs(candidates,0,target,vec);
return ans;
}
};
括号生成
做法:回溯,一共有2*n个括号,左括号<=n,右括号小于左括号,不然无法匹配,按照这个规则匹配即可。
class Solution {
public:
void dfs(vector<string>& ans,string& cur,int open,int close,int n)
{
if(cur.size()==n*2)
{
ans.push_back(cur);
return;
}
if(open<n)
{
cur.push_back('(');
dfs(ans,cur,open+1,close,n);
cur.pop_back();
}
if(close<open)
{
cur.push_back(')');
dfs(ans,cur,open,close+1,n);
cur.pop_back();
}
}
vector<string> generateParenthesis(int n) {
vector<string> ans;
string cur;
dfs(ans,cur,0,0,n);
return ans;
}
};
单词搜索
做法:非优化版本,做一个标记数组,然后搜寻整个图,开始遍历即可,不知道为啥自己写的一直有问题,先不整了
class Solution {
public:
bool check(vector<vector<char>>& board, vector<vector<int>>& visited, int i, int j, string& s, int k) {
if (board[i][j] != s[k]) {
return false;
} else if (k == s.length() - 1) {
return true;
}
visited[i][j] = true;
vector<pair<int, int>> directions{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
bool result = false;
for (const auto& dir: directions) {
int newi = i + dir.first, newj = j + dir.second;
if (newi >= 0 && newi < board.size() && newj >= 0 && newj < board[0].size()) {
if (!visited[newi][newj]) {
bool flag = check(board, visited, newi, newj, s, k + 1);
if (flag) {
result = true;
break;
}
}
}
}
visited[i][j] = false;
return result;
}
bool exist(vector<vector<char>>& board, string word) {
int h = board.size(), w = board[0].size();
vector<vector<int>> visited(h, vector<int>(w));
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
bool flag = check(board, visited, i, j, word, 0);
if (flag) {
return true;
}
}
}
return false;
}
};
分割回文串
两个做法其实都有一个核心问题。如果假设有串aabd,会进入两种递归[a][a],[aa],然后都会进入对b以及后面回文串得判断,其实这种时候就需要记忆化或者预处理了,这也是两种方法得区别之处
做法一:预处理回文串,然后递归加回溯即可
class Solution {
public:
vector<vector<int>>f;
vector<vector<string>>ret;
vector<string> ans;
int n;
void dfs(const string& s,int i)
{
if(i==n)
{
ret.push_back(ans);
return;
}
for(int j=i;j<n;j++)
{
if(f[i][j])
{
ans.push_back(s.substr(i,j-i+1));
dfs(s,j+1);
ans.pop_back();
}
}
}
vector<vector<string>> partition(string s) {
n=s.size();
f.assign(n,vector<int>(n,true));
for(int i=n-1;i>=0;i--)
{
for(int j=i+1;j<n;j++)f[i][j]=(s[i]==s[j])&&f[i+1][j-1];
}
dfs(s,0);
return ret;
}
};
做法二:记忆化回溯即可
class Solution {
public:
vector<vector<int>> f;
vector<vector<string>>ret;
vector<string> ans;
int n;
void dfs(string &s,int i)
{
if(i==n)
{
ret.push_back(ans);
return;
}
for(int j=i;j<n;j++)
{
if(ispal(s,i,j)==1)
{
ans.push_back(s.substr(i,j-i+1));
dfs(s,j+1);
ans.pop_back();
}
}
}
int ispal(string &s,int i,int j)
{
if(f[i][j])return f[i][j];
if(i>=j)return f[i][j]=1;
return f[i][j]=(s[i]==s[j]?ispal(s,i+1,j-1):-1);
}
vector<vector<string>> partition(string s) {
n=s.size();
f.assign(n,vector<int>(n));
dfs(s,0);
return ret;
}
};
N皇后
做法:经典经典经典。但也有变化,大一的时候用bool函数写,现在则是用哈希表了
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> solutions;
vector<int>queens(n,-1);
unordered_set<int> columns;
unordered_set<int> diagonals1;
unordered_set<int> diagonals2;
dfs(solutions,queens,n,0,columns,diagonals1,diagonals2);
return solutions;
}
void dfs(vector<vector<string>>& solutions,vector<int>& queens,int n,int row,unordered_set<int>& columns,unordered_set<int>&diagonals1,unordered_set<int>& diagonals2)
{
if(row==n)
{
vector<string> board=generate(queens,n);
solutions.push_back(board);
}
else
{
for(int i=0;i<n;i++)
{
if(columns.find(i)!=columns.end())continue;
int diagonal1=row-i;
if(diagonals1.find(diagonal1)!=diagonals1.end())continue;
int diagonal2=row+i;
if(diagonals2.find(diagonal2)!=diagonals2.end())continue;
queens[row]=i;
columns.insert(i);
diagonals1.insert(diagonal1);
diagonals2.insert(diagonal2);
dfs(solutions,queens,n,row+1,columns,diagonals1,diagonals2);
queens[row]=-1;
columns.erase(i);
diagonals1.erase(diagonal1);
diagonals2.erase(diagonal2);
}
}
}
vector<string> generate(vector<int>& queens,int n)
{
vector<string> board;
for(int i=0;i<n;i++)
{
string row=string(n,'.');
row[queens[i]]='Q';
board.push_back(row);
}
return board;
}
};
由于今日出游,加上确实不可能一天全部时间all in算法了,所以刷题会变少,希望能提高效率,珍惜时间吧,最好能在清明节后一两天内刷完hot100,然后进行复习