单词搜索 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.前缀

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;
    }
};

相关推荐
楼田莉子5 小时前
C++学习:C++11关于类型的处理
开发语言·c++·后端·学习
黄卷青灯775 小时前
标定系数为什么会存储在相机模组里面,在标定的时候,算法是在割草机的X3板上运行的啊?
数码相机·算法·相机内参
螺丝钉的扭矩一瞬间产生高能蛋白5 小时前
PID算法基础知识
算法
彷徨而立6 小时前
【C/C++】只知道窗口句柄,如何擦除窗口内容,清理窗口?
c语言·c++·windows
強云6 小时前
匿名命名空间 - c++
c++
云知谷6 小时前
【经典书籍】C++ Primer 第14类虚函数与多态精华讲解
c语言·开发语言·c++·软件工程·团队开发
HVACoder6 小时前
复习下线性代数,使用向量平移拼接两段线
c++·线性代数·算法
电子云与长程纠缠6 小时前
UE5 C++ CVar控制台命令字段使用
c++·学习·ue5
爱coding的橙子6 小时前
每日算法刷题Day77:10.22:leetcode 二叉树bfs18道题,用时3h
算法·leetcode·职场和发展