题目:
Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
For example,
Given words = ["oath","pea","eat","rain"]
and board =
[ ['o','a','a','n'], ['e','t','a','e'], ['i','h','k','r'], ['i','f','l','v'] ]Return
["eat","oath"]
.
Note:
You may assume that all inputs are consist of lowercase letters a-z
.
思路:
如果这道题目的输入只是一个单词,那么设计一个DFS就可以通过。但是由于给出了一组单词,所以简单的DFS被证明无法通过大数据。因此,我们需要想办法对DFS进行剪枝,并对实现进行优化。这里给出两种优化方法:
1)采用前缀树(Trie)进行剪枝。就是首先将要搜索的所有单词都添加到字典树中,然后从地图board中的每一个元素进行开始搜索,如果往上下左右搜索的时候其元素可以在前缀树中找到,那么继续搜索(或者在搜索到某个结点的时候发现已经到了某个结点的末尾,那么就将该单词添加到结果集合中);否则就结束当前分支的搜索。
2)采用特殊字符标记访问过的结点。一般情况下,我们可以另外开辟一个二维数组来标记已经访问过的结点。这里我们可以改变原数组的值,搜索完成之后再改回来。这种方法不仅节省空间,而且运行中速度也更快。
经过这两种方法的优化,我们的DFS算法就可以顺利通过所有测试数据。
代码:
class Solution {
public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
if (board.size() == 0 || board[0].size() == 0) {
return {};
}
Trie *root = new Trie(), *node = NULL; // Add each word to the Trie
for (auto str : words) {
node = root;
for (auto ch : str) {
if (!node->child[ch - 'a']) {
node->child[ch - 'a'] = new Trie();
}
node = node->child[ch - 'a'];
}
node->isWord = true;
}
for (int i = 0; i < board.size(); ++i) { // Apply DFS
for (int j = 0; j < board[0].size(); ++j) {
DFS(board, root->child[board[i][j] - 'a'], i, j, "");
}
}
return ret;
}
private:
struct Trie {
vector<Trie*> child;
bool isWord;
Trie() : child(vector<Trie*>(26, NULL)), isWord(false){}
};
void DFS(vector<vector<char>> &board, Trie *root, int x, int y, string str) {
int row_num = board.size(), col_num = board[0].size();
if (!root || board[x][y] == '#') {
return;
}
str += board[x][y];
if (root->isWord) {
ret.push_back(str);
root->isWord = false; // Important: delte this word
}
char ch = board[x][y]; // Backup board[x][y] for efficiency
board[x][y] = '#';
if(x + 1 < row_num) {
DFS(board, root->child[board[x+1][y]-'a'], x+1, y, str);
}
if(x - 1 >= 0) {
DFS(board, root->child[board[x-1][y]-'a'], x-1, y, str);
}
if(y + 1 < col_num) {
DFS(board, root->child[board[x][y+1]-'a'], x, y+1, str);
}
if(y - 1 >= 0) {
DFS(board, root->child[board[x][y-1]-'a'], x, y-1, str);
}
board[x][y] = ch;
}
vector<string> ret;
};