单词搜索 II · Word Search II
https://leetcode.cn/problems/word-search-ii/description/
https://www.jiuzhang.com/solutions/word-search-ii
1.当你需要一个一个遍历字符串,矩阵或者其他的,trie帮助你优化遍历过程中可能性。
2.hash换为trire树节约空间
3.前缀
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;}
}
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 usedfor (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;}
}
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 hereroot = 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;}
};