
https://leetcode.cn/problems/word-search-ii/description/
https://www.jiuzhang.com/solutions/word-search-ii
1.当你需要一个一个遍历字符串,矩阵或者其他的,trie帮助你优化遍历过程中可能性。
2.hash换为trire树节约空间
3.前缀

cpp
public class Solution {
public static int[] dx = {0, 1, -1, 0};
public static int[] dy = {1, 0, 0, -1};
/**
* @param board: A list of lists of character
* @param words: A list of string
* @return: A list of string
*/
public List<String> wordSearchII(char[][] board, List<String> words) {
if (board == null || board.length == 0) {
return new ArrayList<>();
}
if (board[0] == null || board[0].length == 0) {
return new ArrayList<>();
}
boolean[][] visited = new boolean[board.length][board[0].length];
Map<String, Boolean> prefixIsWord = getPrefixSet(words);
Set<String> wordSet = new HashSet<>();
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
visited[i][j] = true;
dfs(board, visited, i, j, String.valueOf(board[i][j]), prefixIsWord, wordSet);
visited[i][j] = false;
}
}
return new ArrayList<String>(wordSet);
}
private Map<String, Boolean> getPrefixSet(List<String> words) {
Map<String, Boolean> prefixIsWord = new HashMap<>();
for (String word : words) {
for (int i = 0; i < word.length() - 1; i++) {
String prefix = word.substring(0, i + 1);
if (!prefixIsWord.containsKey(prefix)) {
prefixIsWord.put(prefix, false);
}
}
prefixIsWord.put(word, true);
}
return prefixIsWord;
}
private void dfs(char[][] board,
boolean[][] visited,
int x,
int y,
String word,
Map<String, Boolean> prefixIsWord,
Set<String> wordSet) {
if (!prefixIsWord.containsKey(word)) {
return;
}
if (prefixIsWord.get(word)) {
wordSet.add(word);
}
for (int i = 0; i < 4; i++) {
int adjX = x + dx[i];
int adjY = y + dy[i];
if (!inside(board, adjX, adjY) || visited[adjX][adjY]) {
continue;
}
visited[adjX][adjY] = true;
dfs(board, visited, adjX, adjY, word + board[adjX][adjY], prefixIsWord, wordSet);
visited[adjX][adjY] = false;
}
}
private boolean inside(char[][] board, int x, int y) {
return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
}
}

cpp
class TrieNode { //定义字典树的节点
String word;
HashMap<Character, TrieNode> children; //使用HashMap动态开节点
public TrieNode() {
word = null;
children = new HashMap<Character, TrieNode>();
}
};
class TrieTree{
TrieNode root;
public TrieTree(TrieNode TrieNode) {
root = TrieNode;
}
public void insert(String word) { //字典树插入单词
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
if (!node.children.containsKey(word.charAt(i))) {
node.children.put(word.charAt(i), new TrieNode());
}
node = node.children.get(word.charAt(i));
}
node.word = word;
}
};
public class Solution {
/**
* @param board: A list of lists of character
* @param words: A list of string
* @return: A list of string
*/
public int[] dx = {1, 0, -1, 0}; //搜索方向
public int[] dy = {0, 1, 0, -1};
public void search(char[][] board, //在字典树上dfs查找
int x,
int y,
TrieNode root,
List<String> results) {
if (!root.children.containsKey(board[x][y])) {
return;
}
TrieNode child = root.children.get(board[x][y]);
if (child.word != null) { //如果访问到字典树叶子,将字符串压入result即可
if (!results.contains(child.word)) {
results.add(child.word);
}
}
char tmp = board[x][y];
board[x][y] = 0; // mark board[x][y] as used
for (int i = 0; i < 4; i++) { //向四个方向dfs搜索
if (!isValid(board, x + dx[i], y + dy[i])) {
continue;
}
search(board, x + dx[i], y + dy[i], child, results);
}
board[x][y] = tmp; // revert the mark
}
private boolean isValid(char[][] board, int x, int y) { //检测搜索位置合法
if (x < 0 || x >= board.length || y < 0 || y >= board[0].length) {
return false;
}
return board[x][y] != 0;
}
public List<String> wordSearchII(char[][] board, List<String> words) {
List<String> results = new ArrayList<String>();
TrieTree tree = new TrieTree(new TrieNode());
for (String word : words){
tree.insert(word);
}
for (int i = 0; i < board.length; i++) { //遍历字母矩阵,将每个字母作为单词首字母开始搜索
for (int j = 0; j < board[i].length; j++) {
search(board, i, j, tree.root, results);
}
}
return results;
}
}

cpp
struct Node { //定义字典树的节点
Node * ch[26]; //因为有26个英文字母,开26个长度
string str;
Node() {
for (int i = 0; i < 26; ++i)
ch[i] = NULL;
str = "";
}
};
class Solution {
public:
vector<string> results;
Node * root;
void insert(Node* p, string s) { //字典树插入单词
int len = s.size();
for (int i = 0; i < len; ++i) {
if (p->ch[s[i]-'a'] == NULL) //如果当前节点为空
p->ch[s[i]-'a'] = new Node(); //新建节点
p = p->ch[s[i]-'a']; //继续遍历
}
p->str = s; //最后一个节点保存字符串
}
void search(vector<vector<char> > &board, vector<vector<bool> > &mask, Node* p, int x, int y) { //在字典树上dfs查找
if (p->str != "") { //如果访问到字典树叶子,将字符串压入result即可
results.push_back(p->str);
p->str = "";
}
mask[x][y] = false; //标记mask[x][y],避免重复访问
if (y + 1 < board[0].size() && mask[x][y+1] && p->ch[board[x][y+1]-'a'] != NULL) { //访问[x][y+1]
search(board,mask, p->ch[board[x][y+1]-'a'], x, y+1);
}
if (x + 1 < board.size() && mask[x+1][y] && p->ch[board[x+1][y]-'a'] != NULL) { //访问[x+1][y]
search(board,mask, p->ch[board[x+1][y]-'a'], x+1, y);
}
if (y - 1 >= 0 && mask[x][y-1] && p->ch[board[x][y-1]-'a'] != NULL) { //访问[x][y-1]
search(board,mask, p->ch[board[x][y-1]-'a'], x, y-1);
}
if (x - 1 >= 0 && mask[x-1][y] && p->ch[board[x-1][y]-'a'] != NULL) { //访问[x-1][y]
search(board,mask, p->ch[board[x-1][y]-'a'], x-1, y);
}
mask[x][y] = true; //搜索后mask[x][y]可以访问
}
/**
* @param board: A list of lists of character
* @param words: A list of string
* @return: A list of string
*/
vector<string> wordSearchII(vector<vector<char> > &board, vector<string> &words) {
// write your code here
root = new Node();
int len = words.size();
for (int i = 0; i < len; ++i) { //插入单词构造字典树
insert(root, words[i]);
}
vector<vector<bool> > mask(board.size(), vector<bool>(board[0].size(), true));
if (board.size() < 1) return results;
for (int i = 0; i <board.size(); ++i) { //遍历字母矩阵,将每个字母作为单词首字母开始搜索
for (int j = 0; j < board[0].size(); ++j) {
if (root->ch[board[i][j]-'a'] != NULL) {
search(board, mask, root->ch[board[i][j]-'a'], i, j); //开始dfs搜索
}
}
}
return results;
}
};