LeetCode 212 - Word Search II


Related: LeetCode124 - Word Search
LeetCode Q212 Word Search II | Lei Jiang Coding
Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
For example, given words = ["oath","pea","eat","rain"] and board =
[
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]
Return ["eat","oath"].
You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?
If the current candidate does not exist in all words' prefix, you could stop backtracking immediately. What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not? How about a Trie? If you would like to learn how to implement a basic trie, please work on this problem: Implement Trie (Prefix Tree) first.
X. Use Trie
Time complexity:
Let's think about the naive solution first. The naive solution is we search the board for each board. So for the dict with n words, and assume the ave. length of each word has length of m. Then without using a Trie, the time complexity would be O(n * rows * cols  * 4^m). 

Now let's analyze the time complexity of using a Trie. We put each word into the trie. Search in the Trie takes O(m) time, so the time complexity would be O(rows * cols * m * 4^m). Since mostly m << n, using a trie would save lots of time. 
Some key points:
  1. reuse board to check visited
  2. store word in TrieNode instead of boolean.
  3. remove the word from the trie once it is found.
Some explanations:
For point 1, we always restore the board to it’s original state after the recursive call. So the board remain the same after the search.
For point 2, although the TrieNode stores a String, it just stores a reference to the immutable string already in memory (since the string is already in words). So it doesn’t cost much more space than store boolean.
For point 3, we just need to set the node’s value to null which is a O(1) time operation. This does not only save time on hashing and convert set to list, it also prune some branch in the search. One may also implement a proper deleteoperation to actually delete the nodes in the path. Which one is better depends on the input.
Combing them, Trie is the natural choice. Notice that:
  1. TrieNode is all we need. search and startsWith are useless.
  2. No need to store character at TrieNode. c.next[i] != null is enough.
  3. Never use c1 + c2 + c3. Use StringBuilder.
  4. No need to use O(n^2) extra space visited[m][n].
  5. No need to use StringBuilder. Storing word itself at leaf node is enough.
  6. No need to use HashSet to de-duplicate. Use "one time search" trie.
UPDATE: Thanks to @dietpepsi we further improved from 17ms to 15ms.
  1. 59ms: Use search and startsWith in Trie class like this popular solution.
  2. 33ms: Remove Trie class which unnecessarily starts from root in every dfs call.
  3. 30ms: Use w.toCharArray() instead of w.charAt(i).
  4. 22ms: Use StringBuilder instead of c1 + c2 + c3.
  5. 20ms: Remove StringBuilder completely by storing word instead of boolean in TrieNode.
  6. 20ms: Remove visited[m][n] completely by modifying board[i][j] = '#' directly.
  7. 18ms: check validity, e.g., if(i > 0) dfs(...), before going to the next dfs.
  8. 17ms: De-duplicate c - a with one variable i.
  9. 15ms: Remove HashSet completely. dietpepsi's idea is awesome.
 It seems the total time complexity is O(n * len), where n is the number of words, len is the average length of a word.
https://leetcode.com/problems/word-search-ii/discuss/59784/My-simple-and-clean-Java-code-using-DFS-and-Trie
public List<String> findWords(char[][] board, String[] words) {
    List<String> res = new ArrayList<>();
    TrieNode root = buildTrie(words);
    for (int i = 0; i < board.length; i++) {
        for (int j = 0; j < board[0].length; j++) {
            dfs (board, i, j, root, res);
        }
    }
    return res;
}

public void dfs(char[][] board, int i, int j, TrieNode p, List<String> res) {
    char c = board[i][j];
    if (c == '#' || p.next[c - 'a'] == null) return;
    p = p.next[c - 'a'];
    if (p.word != null) {   // found one
        res.add(p.word);
        p.word = null;     // de-duplicate
    }

    board[i][j] = '#';
    if (i > 0) dfs(board, i - 1, j ,p, res); 
    if (j > 0) dfs(board, i, j - 1, p, res);
    if (i < board.length - 1) dfs(board, i + 1, j, p, res); 
    if (j < board[0].length - 1) dfs(board, i, j + 1, p, res); 
    board[i][j] = c;
}

public TrieNode buildTrie(String[] words) {
    TrieNode root = new TrieNode();
    for (String w : words) {
        TrieNode p = root;
        for (char c : w.toCharArray()) {
            int i = c - 'a';
            if (p.next[i] == null) p.next[i] = new TrieNode();
            p = p.next[i];
       }
       p.word = w;
    }
    return root;
}

class TrieNode {
    TrieNode[] next = new TrieNode[26];
    String word;
}
https://zyfu0408.gitbooks.io/interview-preparation/content/trie%E5%BA%94%E7%94%A8.html
这题还可以跟面试官沟通,询问是不是有某些character一定不会出现的,这样就可以把访问过的character设成一定不会出现的character,而避免使用visited数组。
http://blog.csdn.net/ljiabin/article/details/45846527
如果还按照DFS回溯的方法,逐个检查每个word是否在board里,显然效率是比较低的。我们可以利用Trie数据结构,也就是前缀树。然后dfs时,如果当前形成的单词不在Trie里,就没必要继续dfs下去了。如果当前字符串在trie里,就说明board可以形成这个word。
http://www.cnblogs.com/yrbbest/p/4979650.html
使用Word Search的方法会超时。因为对每一个word我们都要对整个board进行一遍dfs,所以对于每个单词我们的Time Complexity - O(mn * 26L),大集合的话时间会很长,所以不能用这个方法。
据提示我们尝试使用Tire来做。用words里所有的word先建立好Trie,然后再用DFS扫描board就可以了。为什么我们要使用Trie呢?我觉得主要是因为搜索完一个单词之后,可以继续搜索下一个单词,而不用向Brute force搜索完以后要回头重新查找。举个例子,假如单词为sea,seafood,那么搜索到sea后,我们可以继续搜索seafood。 需要注意的是回溯的时候我们依然要进行剪枝操作。访问过的节点,我们和Word Search一样,先mark为"#",dfs之后再mark回来。搜索到的单词,我们可以把isWord设为false,这样可以处理duplicate。这道题目值得好好理解,整理思路。最近做的一些题目都是动不动就要70+ 行, 希望努力修炼能够有所进步,思维和coding能力。
Time Complexity - O(mn * 26L), Space Complexity - O(26L)       <<- 复杂度二刷的时候还要好好分析
    private TrieNode root;
    
    private class TrieNode {
        private final int R = 26;   // Radix R = 26
        public boolean isWord;
        public TrieNode[] next;
        
        public TrieNode() {
            next = new TrieNode[R];
        }
    }
    
    public List<String> findWords(char[][] board, String[] words) {
        List<String> res = new ArrayList<>();
        if(board == null || board.length == 0)
            return res;
        root = new TrieNode();
        
        for(String word : words)            // build Trie
            addWords(word);
        
        StringBuilder sb = new StringBuilder();  // try assemble word
        
        for(int i = 0; i < board.length; i++) {     
            for(int j = 0; j < board[0].length; j++) {
                search(res, sb, root, board, i, j);
            }
        } 
        
        return res;
    }
    
    private void addWords(String word) {            
        if(word == null || word.length() == 0)
            return;
        int d = 0;
        TrieNode node = root;
        
        while(d < word.length()) {
            char c = word.charAt(d);
            if(node.next[c - 'a'] == null)
                node.next[c - 'a'] = new TrieNode();
            node = node.next[c - 'a'];
            d++;
        }
        
        node.isWord = true;       
    }
    
    private void search(List<String> res, StringBuilder sb, TrieNode node, char[][] board, int i, int j) {
        if(i < 0 || j < 0 || i >= board.length || j >= board[0].length)
            return;
        if(board[i][j] == '#')          // pruning
            return;
        char c = board[i][j];    
        
        TrieNode curRoot = node.next[c - 'a'];    // set node here for DFS
        if(curRoot == null)
            return;
        sb.append(c);
        
        if(curRoot.isWord == true) {
            curRoot.isWord = false;
            res.add(sb.toString());    
        } 
        
        board[i][j] = '#';          // mark visited cell to '#'\\
        search(res, sb, curRoot, board, i + 1, j);
        search(res, sb, curRoot, board, i - 1, j);
        search(res, sb, curRoot, board, i, j + 1);
        search(res, sb, curRoot, board, i, j - 1);
        sb.setLength(sb.length() - 1);   
        board[i][j] = c;            // backtracking\\
    }

https://discuss.leetcode.com/topic/14256/my-simple-and-clean-java-code-using-dfs-and-trie/
    Set<String> res = new HashSet<String>();
    
    public List<String> findWords(char[][] board, String[] words) {
        Trie trie = new Trie();
        for (String word : words) {
            trie.insert(word);
        }
        
        int m = board.length;
        int n = board[0].length;
        boolean[][] visited = new boolean[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                dfs(board, visited, "", i, j, trie);
            }
        }
        
        return new ArrayList<String>(res);
    }
    
    public void dfs(char[][] board, boolean[][] visited, String str, int x, int y, Trie trie) {
        if (x < 0 || x >= board.length || y < 0 || y >= board[0].length) return;
        if (visited[x][y]) return;
        
        str += board[x][y];
        if (!trie.startsWith(str)) return;
        
        if (trie.search(str)) {
            res.add(str);
        }
        
        visited[x][y] = true;
        dfs(board, visited, str, x - 1, y, trie);
        dfs(board, visited, str, x + 1, y, trie);
        dfs(board, visited, str, x, y - 1, trie);
        dfs(board, visited, str, x, y + 1, trie);
        visited[x][y] = false;
    }
class TrieNode {
    public TrieNode[] children = new TrieNode[26];
    public String item = "";
    
    // Initialize your data structure here.
    public TrieNode() {
    }
}

class Trie {
    private TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    // Inserts a word into the trie.
    public void insert(String word) {
        TrieNode node = root;
        for (char c : word.toCharArray()) {
            if (node.children[c - 'a'] == null) {
                node.children[c - 'a'] = new TrieNode();
            }
            node = node.children[c - 'a'];
        }
        node.item = word;
    }

    // Returns if the word is in the trie.
    public boolean search(String word) {
        TrieNode node = root;
        for (char c : word.toCharArray()) {
            if (node.children[c - 'a'] == null) return false;
            node = node.children[c - 'a'];
        }
        return node.item.equals(word);
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    public boolean startsWith(String prefix) {
        TrieNode node = root;
        for (char c : prefix.toCharArray()) {
            if (node.children[c - 'a'] == null) return false;
            node = node.children[c - 'a'];
        }
        return true;
    }
}
https://codesolutiony.wordpress.com/2015/05/20/leetcode-word-search-ii/
Use Hashset to remove duplication.
另外如果搜索的路径已经不是字典树是的前缀了就可以直接剪枝返回了。下面是AC代码。因为要避免重复,我先用了一个set存结果,然后再转存到result中。
因此得用trie来保存input的所有string,然后dfs遍历board来看当前的string是否存在于trie中。如果当前string不是trie中任意string的prefix,可以剪枝,不需要继续dfs下去。很好的题目,需要加强
    public List<String> findWords(char[][] board, String[] words) {
        List<String> res = new ArrayList<String>();
        if (board == null || board.length == 0 || board[0].length == 0
|| words == null || words.length == 0) {
            return res;
        }
         
        boolean[][] visited = new boolean[board.length][board[0].length];
        Set<String> noDuplicateInput = new HashSet<String>(Arrays.asList(words));
        Trie trie = new Trie(noDuplicateInput);
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                search(board, i, j, "", visited, trie, res);
            }
        }
        return res;
    }
    private void search(char[][] board, int i, int j,
            String str, boolean[][] visited, Trie trie, List<String> res) {
        if (i < board.length && i >= 0 && j < board[0].length && j >= 0 && visited[i][j] == false) {
            String newStr = str + board[i][j];
            TrieNode endNode = trie.startWith(newStr);//
            if (endNode != null) {
                if (endNode.leaf == true) {
                    res.add(newStr);
                    endNode.leaf = false; //avoid duplicate in result
                }
                visited[i][j] = true;
                search(board, i+1, j, newStr, visited, trie, res);
                search(board, i-1, j, newStr, visited, trie, res);
                search(board, i, j+1, newStr, visited, trie, res);
                search(board, i, j-1, newStr, visited, trie, res);
                visited[i][j] = false;
            }
        }
    }
    class Trie {
        TrieNode root;
        public Trie(Set<String> strs) {
            root = new TrieNode();
            for (String str : strs) {
                add(str);
            }
        }
        //gets the last node in the tree that matches the str, return null if not match
        public TrieNode startWith(String str) {
            TrieNode res = null;
            TrieNode curRoot = root;
            for (int i = 0; i < str.length(); i++) {
                if (curRoot.children != null && curRoot.children.get(str.charAt(i)) != null) {
                    if (i == str.length() - 1) {
                        res = curRoot.children.get(str.charAt(i));
                    }
                    curRoot = curRoot.children.get(str.charAt(i));
                } else {
                    break;
                }
            }
            return res;
        }
        public void add(String str) {
            TrieNode curRoot = root;
            for (int i = 0; i < str.length(); i++) {
                if (curRoot.children == null) {
                    curRoot.children = new HashMap<Character, TrieNode>();
                }
                if (curRoot.children.get(str.charAt(i)) == null) {
                    curRoot.children.put(str.charAt(i), new TrieNode(str.charAt(i)));
                }
                if (i == str.length() - 1) {
                    curRoot.children.get(str.charAt(i)).leaf = true;
                }
                curRoot = curRoot.children.get(str.charAt(i));
            }
        }
        public boolean contains(String str) {
            TrieNode lastNode = startWith(str);
            if (lastNode == null || lastNode.leaf == false) {
                return false;
            }
            return true;
        }
    }
    class TrieNode {
        boolean leaf;
        char ch;
        Map<Character, TrieNode> children;
        public TrieNode() { }
        public TrieNode(char ch) {
            this.ch = ch;
        }
    }
http://www.jiuzhang.com/solutions/word-search-ii/
Where is the visited hashset to avoid re-computation?
    class TrieNode {
        String s;
         boolean isString;
         HashMap<Character, TrieNode> subtree;
         public TrieNode() {
             isString = false;
             subtree = new HashMap<Character, TrieNode>();
             s = "";
         }
    };


    class TrieTree{
        TrieNode root ;
        public TrieTree(TrieNode TrieNode) {
            root = TrieNode;
        }
        public void insert(String s) {
            TrieNode now = root;
            for (int i = 0; i < s.length(); i++) {
                if (!now.subtree.containsKey(s.charAt(i))) {
                    now.subtree.put(s.charAt(i), new TrieNode());
                }
                now  =  now.subtree.get(s.charAt(i));
            }
            now.s = s;
            now.isString  = true;
        }
        public boolean find(String s){
            TrieNode now = root;
            for (int i = 0; i < s.length(); i++) {
                if (!now.subtree.containsKey(s.charAt(i))) {
                    return false;
                }
                now  =  now.subtree.get(s.charAt(i));
            }
            return now.isString ;
        }
    };

    public int []dx = {1, 0, -1, 0};
    public int []dy = {0, 1, 0, -1};
    
    public void search(char[][] board, int x, int y, TrieNode root, ArrayList<String> ans, String res) {    
        if(root.isString == true)
        {
            if(!ans.contains(root.s)){ //slow
                ans.add(root.s);
            }
        }
        if(x < 0 || x >= board.length || y < 0 || y >= board[0].length || board[x][y]==0 || root == null)
            return ;
        if(root.subtree.containsKey(board[x][y])){
            for(int i = 0; i < 4; i++){
                char now = board[x][y];
                board[x][y] = 0;
                search(board, x+dx[i], y+dy[i], root.subtree.get(now), ans, res);
                board[x][y] = now;
            }
        }
        
    }
    
    public ArrayList<String> wordSearchII(char[][] board, ArrayList<String> words) {
        ArrayList<String> ans = new ArrayList<String>();
        
        TrieTree tree = new TrieTree(new TrieNode());
        for(String word : words){
            tree.insert(word);
        }
        String res = ""; 
        for(int i = 0; i < board.length; i++){
            for(int j = 0; j < board[i].length; j++){
                search(board, i, j, tree.root, ans, res);
            }
        }
        return ans;        
    }


If the current candidate does not exist in all words' prefix, we can stop backtracking immediately. This can be done by using a trie structure.
public class Solution {
    Set<String> result = new HashSet<String>(); 
 
    public List<String> findWords(char[][] board, String[] words) {
        //HashSet<String> result = new HashSet<String>();
 
        Trie trie = new Trie();
        for(String word: words){
            trie.insert(word);
        }
 
        int m=board.length;
        int n=board[0].length;
 
        boolean[][] visited = new boolean[m][n];
 
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
               dfs(board, visited, "", i, j, trie);
            }
        }
 
        return new ArrayList<String>(result);
    }
 
    public void dfs(char[][] board, boolean[][] visited, String str, int i, int j, Trie trie){
        int m=board.length;
        int n=board[0].length;
 
        if(i<0 || j<0||i>=m||j>=n){
            return;
        }
 
        if(visited[i][j])
            return;
 
        str = str + board[i][j];
 
        if(!trie.startsWith(str))
            return;
 
        if(trie.search(str)){
            result.add(str);
        }
 
        visited[i][j]=true;
        dfs(board, visited, str, i-1, j, trie);
        dfs(board, visited, str, i+1, j, trie);
        dfs(board, visited, str, i, j-1, trie);
        dfs(board, visited, str, i, j+1, trie);
        visited[i][j]=false;
    }
}
//Trie Node
class TrieNode{
    public TrieNode[] children = new TrieNode[26];
    public String item = "";
}
 
//Trie
class Trie{
    public TrieNode root = new TrieNode();
 
    public void insert(String word){
        TrieNode node = root;
        for(char c: word.toCharArray()){
            if(node.children[c-'a']==null){
                node.children[c-'a']= new TrieNode();
            }
            node = node.children[c-'a'];
        }
        node.item = word;
    }
 
    public boolean search(String word){
        TrieNode node = root;
        for(char c: word.toCharArray()){
            if(node.children[c-'a']==null)
                return false;
            node = node.children[c-'a'];
        }
        if(node.item.equals(word)){
            return true;
        }else{
            return false;
        }
    }
 
    public boolean startsWith(String prefix){
        TrieNode node = root;
        for(char c: prefix.toCharArray()){
            if(node.children[c-'a']==null)
                return false;
            node = node.children[c-'a'];
        }
        return true;
    }
}
http://buttercola.blogspot.com/2015/09/word-search-ii.html
    private int rows;
    private int cols;
    public List<String> findWords(char[][] board, String[] words) {
        List<String> result = new ArrayList<String>();
        if (board == null || board.length == 0 || words == null || words.length == 0) {
            return result;
        }
         
        Set<String> set = new HashSet<String>();
         
        Trie trie = new Trie();
         
        this.rows = board.length;
        this.cols = board[0].length;
         
        // Step 1: insert all words into a trie
        for (String word : words) {
            trie.insert(word);
        }
         
        // Step 2: search the board
        boolean[][] visited = new boolean[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                searchBoardHelper(board, i, j, "", visited, trie, set);
            }
        }
         
        return new ArrayList<String>(set);
    }
     
     
    private void searchBoardHelper(char[][] board, int row, int col, String word,
                                      boolean[][] visited, Trie trie, Set<String> set) {
        if (row < 0 || row >= rows || col < 0 || col >= cols) {
            return;
        }
         
        if (visited[row][col]) {
            return;
        }
         
        word += board[row][col];
         
        if (!trie.searchPrefix(word)) {
            return;
        }
         
        if (trie.search(word)) { //\\ no need to search again, just check whether the node is a leaf
            set.add(word);
        }         
        visited[row][col] = true;
         
        searchBoardHelper(board, row - 1, col, word, visited, trie, set);
        searchBoardHelper(board, row + 1, col, word, visited, trie, set);
        searchBoardHelper(board, row, col - 1, word, visited, trie, set);
        searchBoardHelper(board, row, col + 1, word, visited, trie, set);
         
        visited[row][col] = false;
    }
     
    class Trie {
        private TrieNode root = new TrieNode();
         
        // Insert a word
        void insert(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    curr.children[character - offset] =
                        new TrieNode(character, i == s.length() - 1 ? true : false);
                } else {
                    if (i == s.length() - 1) {
                        curr.children[character - offset].leaf = true;
                    }
                }
                curr = curr.children[character - offset];
            }
        }
         
         
        // Search a word
        boolean search(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    return false;
                }
                curr = curr.children[character - offset];
            }
             
            if (curr != null && !curr.leaf) {
                return false;
            }
             
            return true;
        }
         
        // Search for prefix
        boolean searchPrefix(String s) {
            TrieNode curr = root;
            int offset = 'a';
            for (int i = 0; i < s.length(); i++) {
                char character = s.charAt(i);
                if (curr.children[character - offset] == null) {
                    return false;
                }
                 
                curr = curr.children[character - offset];
            }
             
            return true;
        }
    }
     
    class TrieNode {
        char val;
        boolean leaf;
        TrieNode[] children;
         
        public TrieNode() {
            this.val = '\0';
            this.children = new TrieNode[26];
        }
         
        public TrieNode(char val, boolean leaf) {
            this.val = val;
            this.leaf = leaf;
            this.children = new TrieNode[26];
        }
    }
http://www.huhaoyu.com/leetcode-word-search-2/
这种基于哈希表的算法,每次只查询一个单词,显然这会导致重复工作。所以正确的做法是构造一个字典树(Trie Tree),将字典树作为一个待查询的字符串集,在board中进行查找。
毋庸置疑,基于字典树的算法每次都查询整个字符串集,避免了相同前缀多次搜索的问题
http://shibaili.blogspot.com/2015/06day-108-add-and-search-word-data.html
You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?
If the current candidate does not exist in all words' prefix, you could stop backtracking immediately. What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not? How about a Trie? If you would like to learn how to implement a basic trie, please work on this problem: Implement Trie (Prefix Tree) first.
    void search(vector<string> &rt, vector<vector<char>>& board,
            vector<vector<bool> > &visit, Trie &trie, string word, int row, int col, unordered_set<string> &hadIt) {
        if (row < 0 || row >= board.size() || col < 0 || col >= board[0].size() || visit[row][col]) {
            return;
        }
        word += board[row][col];
        visit[row][col] = true;
        if (hadIt.find(word) == hadIt.end() && trie.search(word)) {
            hadIt.insert(word);
            rt.push_back(word);
        }
         
        if (trie.startsWith(word)) {
            search(rt,board,visit,trie,word,row + 1,col,hadIt);
            search(rt,board,visit,trie,word,row - 1,col,hadIt);
            search(rt,board,visit,trie,word,row,col + 1,hadIt);
            search(rt,board,visit,trie,word,row,col - 1,hadIt);
        }
        visit[row][col] = false;
    }
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
        Trie trie;
        for (int i = 0; i < words.size(); i++) {
            trie.insert(words[i]);
        }
         
        vector<string> rt;
        vector<vector<bool> > visit(board.size(),vector<bool>(board[0].size(),false));
        unordered_set<string> hadIt;
        for (int i = 0; i < board.size(); i++) {
            for (int j = 0; j <board[0].size(); j++) {
                search(rt,board,visit,trie,"",i,j,hadIt);
            }
        }
         
        return rt;
    }

http://www.cnblogs.com/linxiong/p/4518192.html
Word Search Problem - Non-recursive Solution
http://www.bo-yang.net/2014/07/28/word-search/
X. Simple DFS
http://blog.csdn.net/xudli/article/details/45864915
  1.     public List<String> findWords(char[][] board, String[] words) {  
  2.         List<String> res = new ArrayList<String>();  
  3.         if(board==null || words==null || board.length==0 || words.length==0return res;  
  4.         boolean[][] visited = new boolean[board.length][board[0].length];   
  5.           
  6.         Set<String> dict = new HashSet<String>(Arrays.asList(words));  
  7.           
  8.         for(int i=0; i<board.length; i++) {  
  9.             for(int j=0; j<board[0].length; j++) {  
  10.                 search(board, visited, dict, i, j, new StringBuilder(), res);  
  11.             }  
  12.         }  
  13.         return res;  
  14.     }  
  15.       
  16.     private void search(char[][] board,boolean[][] visited,Set<String> dict,int i,int j, StringBuilder sb, List<String> res) {  
  17.         if(i<0 || i>board.length-1 || j<0 || j>board[0].length-1 || visited[i][j])  return;  
  18.         sb.append(board[i][j]);  
  19.         visited[i][j] = true;  
  20.         if(dict.contains(sb.toString()))   
  21.             res.add(sb.toString());  
  22.           
  23.         search(board, visited, dict, i-1, j, sb, res);  
  24.         search(board, visited, dict, i+1, j, sb, res);  
  25.         search(board, visited, dict, i, j-1, sb, res);  
  26.         search(board, visited, dict, i, j+1, sb, res);  
  27.           
  28.         sb.deleteCharAt(sb.length() - 1);  
  29.         visited[i][j] = false;  
  30.     }  
X.
http://www.programcreek.com/2014/06/leetcode-word-search-ii-java/
public List<String> findWords(char[][] board, String[] words) {
 ArrayList<String> result = new ArrayList<String>();
 
 int m = board.length;
 int n = board[0].length;
 
 for (String word : words) {
  boolean flag = false;
  for (int i = 0; i < m; i++) {
   for (int j = 0; j < n; j++) {
    char[][] newBoard = new char[m][n];
    for (int x = 0; x < m; x++)
     for (int y = 0; y < n; y++)
      newBoard[x][y] = board[x][y];
 
    if (dfs(newBoard, word, i, j, 0)) {
     flag = true;
    }
   }
  }
  if (flag) {
   result.add(word);
  }
 }
 
 return result;
}
 
public boolean dfs(char[][] board, String word, int i, int j, int k) {
 int m = board.length;
 int n = board[0].length;
 
 if (i < 0 || j < 0 || i >= m || j >= n || k > word.length() - 1) {
  return false;
 }
 
 if (board[i][j] == word.charAt(k)) {
  char temp = board[i][j];
  board[i][j] = '#';
 
  if (k == word.length() - 1) {
   return true;
  } else if (dfs(board, word, i - 1, j, k + 1)
    || dfs(board, word, i + 1, j, k + 1)
    || dfs(board, word, i, j - 1, k + 1)
    || dfs(board, word, i, j + 1, k + 1)) {
   board[i][j] = temp;
   return true;
  }
 
 } else {
  return false;
 }
 
 return false;
}
Read full article from LeetCode Q212 Word Search II | Lei Jiang Coding

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts