212. 单词搜索 II (Trie&dfs)
对方格每个位置进行 d f s dfs dfs,同时用一个 T r i e Trie Trie当前走的字符串是否为 T r i e Trie Trie的前缀。
为了更快,当我们找到一个字符串时,就把它从 T r i e Trie Trie删去。
struct TrieNode {
string word;
int num;
unordered_map<char, TrieNode *> children;
TrieNode() {
this->word = "";
num=0;
}
};
void insertTrie(TrieNode * root, const string & word) {
TrieNode * node = root;
for (auto c : word) {
node->num++;
if (!node->children.count(c)) {
node->children[c] = new TrieNode();
}
node = node->children[c];
}
node->word = word;
}
void erase(TrieNode * root, const string & word) {
TrieNode * node = root;
for (auto c : word) {
node->num--;
if (!node->num) {
return;
}
node = node->children[c];
}
}
class Solution {
public:
int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
TrieNode * _root = new TrieNode();
bool dfs(vector<vector<char>>& board, int x, int y, TrieNode * root, vector<string> & res) {
if(!root->num) return false; //这个剪枝很重要
char ch = board[x][y];
if (!root->children.count(ch)) {
return false;
}
root = root->children[ch];
if (root->word.size() > 0 ) {
res.push_back(root->word);
erase(_root,root->word);
root->word = "";
}
board[x][y] = '#';
for (int i = 0; i < 4; ++i) {
int nx = x + dirs[i][0];
int ny = y + dirs[i][1];
if (nx >= 0 && nx < board.size() && ny >= 0 && ny < board[0].size()) {
if (board[nx][ny] != '#'){
dfs(board, nx, ny, root,res);
}
}
}
board[x][y] = ch;
return true;
}
vector<string> findWords(vector<vector<char>> & board, vector<string> & words) {
vector<string> res;
for (auto & word: words)
insertTrie(_root,word);
for (int i = 0; i < board.size(); ++i)
for(int j = 0; j < board[0].size(); ++j)
dfs(board, i, j, _root, res);
return res;
}
};
时间复杂度: O ( n m 3 l − 1 ) O(nm3^{l-1}) O(nm3l−1), l l l是最长字符串长度,因为同一个单词的一个格子不能多次使用,所以每次最多3个方向选择。