原题
几个月前使用回溯可以通过,代码如下:
class Solution {
private:
vector<string> ans;
public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
int m=board.size();
if(!m) return {};
int n=board[0].size();
for(int i=0;i<words.size();i++){
vector<vector<int>> visited(m,vector<int>(n,0));
int j,k;
bool flag=0;
for(j=0;j<m;j++){
for(k=0;k<n;k++){
if(board[j][k]==words[i][0])
if(trackback(visited,board,words[i],0,j,k)){
flag=true;
break;
}
}
if(flag) break;
}
}
return ans;
}
int trackback(vector<vector<int>>& visited, vector<vector<char>>& board, string word, int pos, int i, int j){
if(pos>=word.size()){
ans.push_back(word);
return 1;
}
if(i>=board.size() || i<0) return 0;
if(j>=board[0].size() || j<0) return 0;
if(visited[i][j] || board[i][j]!=word[pos]) return 0;
visited[i][j]=1;
if(trackback(visited, board, word, pos+1,i+1, j) ||
trackback(visited, board, word, pos+1,i-1, j) ||
trackback(visited, board, word, pos+1,i, j+1) ||
trackback(visited, board, word, pos+1,i, j-1)) return 1;
visited[i][j]=0;
return 0;
}
};
原理很简单,就是向上下左右递归寻找,找到完整单词则计入结果集。
今天每日一题再次遇到,回溯超时:
class Solution {
public:
static constexpr int direcs[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int m, n;
vector<string> res;
int flag;
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
m=board.size(), n=board[0].size();
for(auto& word:words){
flag=0;
vector<vector<int>> visited(m ,vector<int>(n,0));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
visited[i][j]=1;
if(board[i][j]==word[0]) traceback(board, i, j, word, 0, visited);
visited[i][j]=0;
}
}
}
return res;
}
void traceback(vector<vector<char>>& board, int i, int j, string& word, int pos, vector<vector<int>>& visited){
if(flag==1) return ;
if(board[i][j]!=word[pos]) return ;
if(pos==word.length()-1 && board[i][j]==word[word.length()-1]){
res.push_back(word);
flag=1;
return ;
}
if(pos>=word.length()-1) return ;
for(auto& direc:direcs){
int x=i+direc[0], y=j+direc[1];
if(x>=0 && x<m && y>=0 && y<n && visited[x][y]==0){
visited[x][y]=1;
traceback(board, x, y, word, pos+1, visited);
visited[x][y]=0;
}
}
}
};
蛮无语的,相似的代码,之前超过100%用户,现在通过不了。
只能考虑前缀树了。
先默写前缀树的插入和搜索代码:
//前缀树
class Tire{
public:
string word;
unordered_map<int, Tire*> next;
Tire(){
word="";
}
};
void insertTire(Tire* root, string word){
Tire* node=root;
for(char ch:word){
if(node->next[ch-'a']==NULL){
node->next[ch-'a']=new Tire();
}
node=node->next[ch-'a'];
}
node->word=word;
}
bool searchTire(Tire* root, string word){ // 寻找是否包含word这个单词
Tire* node=root;
for(char ch:word){
node=node->next[ch-'a'];
if(node==NULL) return false;
}
return node->word==word;
}
Tire* searchPrefix(Tire* root, string prefix){ // 寻找是否包含这个前缀,包含则返回前缀的最后节点
Tire* node=root;
for(char ch:prefix){
node=node->next[ch-'a'];
if(node==NULL) return NULL;
}
return node;
}
然后使用这个线段树解决这一题:
class Tire{
public:
string word;
unordered_map<int, Tire*> next;
Tire(){
word="";
}
};
void insertTire(Tire* root, string word){
Tire* node=root;
for(char ch:word){
if(node->next[ch-'a']==NULL){
node->next[ch-'a']=new Tire();
}
node=node->next[ch-'a'];
}
node->word=word;
}
bool searchTire(Tire* root, string word){ // 寻找是否包含word这个单词
Tire* node=root;
for(char ch:word){
node=node->next[ch-'a'];
if(node==NULL) return false;
}
return node->word==word;
}
Tire* searchPrefix(Tire* root, string prefix){ // 寻找是否包含这个前缀,包含则返回前缀的最后节点
Tire* node=root;
for(char ch:prefix){
node=node->next[ch-'a'];
if(node==NULL) return NULL;
}
return node;
}
class Solution {
private:
vector<string> res;
public:
int dircts[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
int m=board.size(), n=board[0].size();
Tire* root=new Tire();
for(auto& word:words) insertTire(root, word);
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
traceback(board, i, j, root);
}
}
return res;
}
void traceback(vector<vector<char>>& board, int x, int y, Tire* root){
char ch=board[x][y];
if(!root->next[ch-'a']) return;
root=root->next[ch-'a'];
if(root->word.length()>0){
//能继续往后遍历,说明当前路径上的节点都再前缀树中,不然就从上边的return返回了。所以如果当前节点是某个单词的结尾,则该单词科放入结果集
res.push_back(root->word);
root->word=""; // 再前缀树中将当前节点保存到单词情况,防止重复加入结果集。
}
board[x][y]='#';
for(auto& dirct:dircts){
int _x=x+dirct[0], _y=y+dirct[1];
if(_x>=0 && _x<board.size() && _y>=0 && _y<board[0].size()){
traceback(board, _x, _y, root);
}
}
board[x][y]=ch;
}
};
关键步骤都在注释中。