题目:
给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
示例:
输入: words =["oath","pea","eat","rain"]
and board = [ ['o','a','a','n'], ['e','t','a','e'], ['i','h','k','r'], ['i','f','l','v'] ] 输出:["eat","oath"]
说明:
你可以假设所有输入都由小写字母 a-z
组成。
提示:
- 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
- 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。
虽然之前做过前缀树的题目,但是还是不知道具体该怎么实现,百度了两个解法,阅读后给出自己的答案:
两个解法:https://blog.youkuaiyun.com/Viscu/article/details/82470435
https://blog.youkuaiyun.com/liujunzxcv/article/details/79849665
C#代码:
public class Trie
{
private class Node
{
public Node[] children;
public bool isEnd = false;
public Node()
{
children = new Node[26];
isEnd = false;
}
}
private Node rootNode = null;
/** Initialize your data structure here. */
public Trie()
{
rootNode = new Node();
}
/** Inserts a word into the trie. */
public void Insert(String word)
{
Node currNode = rootNode;
for (int i = 0; i < word.Length; i++)
{
if (currNode.children[word[i] - 'a'] == null)
{
currNode.children[word[i] - 'a'] = new Node();
}
currNode = currNode.children[word[i] - 'a'];
}
currNode.isEnd = true;
}
/** Returns if the word is in the trie. */
public bool Search(String word)
{
Node currNode = rootNode;
for (int i = 0; i < word.Length; i++)
{
if (currNode.children[word[i] - 'a'] == null)
{
return false;
}
currNode = currNode.children[word[i] - 'a'];
}
return currNode.isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public bool StartsWith(String prefix)
{
Node currNode = rootNode;
for (int i = 0; i < prefix.Length; i++)
{
if (currNode.children[prefix[i] - 'a'] == null)
{
return false;
}
currNode = currNode.children[prefix[i] - 'a'];
}
return true;
}
}
public class Solution
{
public int[] dx = { 1, -1, 0, 0 };
public int[] dy = { 0, 0, 1, -1 };
public List<string> res = new List<string>();
public bool[][] vis;
public IList<string> FindWords(char[][] board, string[] words)
{
int n = words.Length;
int rn = board.Length;
int cn = board[0].Length;
if (rn > 0 && cn > 0 && n > 0)
{
Trie trie = new Trie();
foreach (string word in words)
{
trie.Insert(word);
}
vis = new bool[rn][];
for (int i = 0; i < rn; i++)
{
vis[i] = new bool[cn];
}
for (int i = 0; i < rn; i++)
{
for (int j = 0; j < cn; j++)
{
Dfs(trie, i, j, board, "");
}
}
}
res.Sort();
return res;
}
public void Dfs(Trie trie, int x, int y, char[][] board, string curStr)
{
int rn = board.Length;
int cn = board[0].Length;
if (x < 0 || y < 0 || x >= rn || y >= cn || vis[x][y])
{
return;
}
curStr = curStr + board[x][y];
if (trie.Search(curStr))
{
if (!res.Contains(curStr))
{
res.Add(curStr);
}
}
if (trie.StartsWith(curStr))
{
vis[x][y] = true;
for (int i = 0; i < 4; i++)
{
Dfs(trie, x + dx[i], y + dy[i], board, curStr);
}
}
vis[x][y] = false;
}
}