题目:212. 单词搜索 II
难度: 困难
题目:
给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
示例1
输入:board = [[“o”,“a”,“a”,“n”],[“e”,“t”,“a”,“e”],[“i”,“h”,“k”,“r”],[“i”,“f”,“l”,“v”]], words = [“oath”,“pea”,“eat”,“rain”]
输出:[“eat”,“oath”]
示例2
输入:board = [[“a”,“b”],[“c”,“d”]], words = [“abcb”]
输出:[]
提示:
- m == board.length
- n == board[i].length
- 1 <= m, n <= 12
- board[i][j] 是一个小写英文字母
- 1 <= words.length <= 3 * 104
- 1 <= words[i].length <= 10
- words[i] 由小写英文字母组成
- words 中的所有字符串互不相同
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-search-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
这题的思路是前缀树+回溯,用前缀树存储某个单词的信息,四个方向回溯查找单词。
前缀树,也称单词数,单词只在某些结点上存储,同时每个结点都存储了其后缀。
class Solution {
public:
struct TrieNode
{
string word;
unordered_map<char, TrieNode*> next;
TrieNode()
{
this->word = "";
}
};
void trie_insert(TrieNode* root, string& word)
{
TrieNode* node = root;
for (auto& ch : word)
{
if (!node->next.count(ch))
{
node->next[ch] = new TrieNode();
}
node = node->next[ch];
}
node->word = word;
}
int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
bool DFS(TrieNode* root, vector<vector<char>>& board, int x, int y, set<string>& res)
{
char ch = board[x][y];
if (!root->next.count(ch))
{
return false;
}
root = root->next[ch];
if (!root->word.empty())
{
res.insert(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(root, board, nx, ny, res);
}
}
}
board[x][y] = ch;
return true;
}
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
TrieNode* root = new TrieNode();
set<string> res;
vector<string> ans;
//构建前缀树
for (auto& word : words)
{
trie_insert(root, word);
}
//DFS
for (int i = 0; i < board.size(); i++)
{
for (int j = 0; j < board[0].size(); j++)
{
DFS(root, board, i, j, res);
}
}
//处理输出
for (auto& word : res)
{
ans.push_back(word);
}
return ans;
}
};