zoukankan      html  css  js  c++  java
  • Leetcode: Word Search II

    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"].

    如果跟Word Search做法一样,还按照DFS回溯的方法,逐个检查每个word是否在board里,显然效率是比较低的。我们可以利用Trie数据结构,也就是前缀树。然后dfs时,如果当前形成的单词不在Trie里,就没必要继续dfs下去了。如果当前字符串在trie里,就说明board可以形成这个word。

    这道题很好的体现了Trie的优势:不用Trie, 我们就得把String[] words里面的word一个一个去board里做dfs(以每个点为起点做一次),很耗时。有了Trie,我们可以用Trie存着所有word,然后去board里做一次dfs(以每个点为起点做一次)

    需要小心的几点,我犯了错误:

    1. 有可能board里面有多份某一个word,dfs会把它们都找出来,但是result set只需要添加一次就好了

    有人是这样做的:Set<String> res = new HashSet<String>();

    return的时候: return new ArrayList<String>(res);

    2. 第21行 string concatenation actually creates a new string, and have the reference cur refer to the new string. It does not change the original content, so no changes will cause to the original content after the recursion. We do not need to do string shrinking like this cur = cur.substring(0, cur.length()-1) at the end of the recursion;

    To be specific: suppose String str = "ab" is the original content, we use str to be the argument to call function dfs. In dfs function, String cur gets the reference to original object "ab". Now both String str and String cur refers to the original "ab". Now we do: cur = cur + 'a'. The '+' actually creates a deep copy of "ab" in the memory with the content "aba", an entirely new String object. And we assign reference cur to this new String object. Whatever changes we do to the new string object referred by cur, it does not influence the original string object str. So at the end of the dfs function, we either shrink or not shrink cur, it simply doesn't matter.

     1 class Solution {
     2     public class TrieNode {
     3         TrieNode[] children;
     4         boolean isWord;
     5         public TrieNode() {
     6             this.children = new TrieNode[26];
     7             this.isWord = false;
     8         }
     9     }
    10     
    11     public class Trie {
    12         TrieNode root;
    13         
    14         public Trie() {
    15             this.root = new TrieNode();
    16         }
    17         
    18         public void insertWord(String word) {
    19             if (word == null || word.length() == 0) return;
    20             TrieNode cur = this.root;
    21             for (int i = 0; i < word.length(); i ++) {
    22                 if (cur.children[word.charAt(i) - 'a'] == null) {
    23                     cur.children[word.charAt(i) - 'a'] = new TrieNode();
    24                 }
    25                 cur = cur.children[word.charAt(i) - 'a'];
    26             }
    27             cur.isWord = true;
    28         }
    29         
    30         public boolean search(String word) {
    31             TrieNode cur = this.root;
    32             for (int i = 0; i < word.length(); i ++) {
    33                 if (cur.children[word.charAt(i) - 'a'] == null) return false;
    34                 cur = cur.children[word.charAt(i) - 'a'];
    35             }
    36             return cur.isWord;
    37         }
    38         
    39         public boolean startsWith(String prefix) {
    40             TrieNode cur = this.root;
    41             for (int i = 0; i < prefix.length(); i ++) {
    42                 if (cur.children[prefix.charAt(i) - 'a'] == null) return false;
    43                 cur = cur.children[prefix.charAt(i) - 'a'];
    44             }
    45             return true;
    46         }
    47     }
    48     
    49     public List<String> findWords(char[][] board, String[] words) {
    50         List<String> res = new ArrayList<>();
    51         if (words == null || words.length == 0) return res;
    52         
    53         Trie tr = new Trie(); 
    54         for (String word : words) {
    55             tr.insertWord(word);
    56         }
    57         
    58         Set<String> set = new HashSet<>();
    59         for (int i = 0; i < board.length; i ++) {
    60             for (int j = 0; j < board[0].length; j ++) {
    61                 dfs(board, i, j, "", tr, set);
    62             }
    63         }
    64         for (String item : set) {
    65             res.add(item);
    66         }
    67         return res;
    68     }
    69     
    70     public void dfs(char[][] board, int i, int j, String cur, Trie tr, Set<String> set) {
    71         if (tr.search(cur)) {
    72             set.add(cur);
    73         }
    74         if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || board[i][j] == '*') 
    75             return;
    76         if (!tr.startsWith(cur)) return;
    77         char c = board[i][j];
    78         board[i][j] = '*';
    79         dfs(board, i - 1, j, cur + c, tr, set);
    80         dfs(board, i + 1, j, cur + c, tr, set);
    81         dfs(board, i, j - 1, cur + c, tr, set);
    82         dfs(board, i, j + 1, cur + c, tr, set);
    83         board[i][j] = c;
    84     }
    85 }
  • 相关阅读:
    摘记
    【题解】网格 & Single Cut of Failure(trick:答案上界)
    题解 CF1404C 【Fixed Point Removal】
    Linux IO模型知识梳理
    Java IO模型知识梳理
    如何回答什么是线程安全?
    MySQL主从复制与备份
    MySQL的高性能索引策略
    CAS(乐观锁)的原理解析
    Java虚拟机的类加载机制
  • 原文地址:https://www.cnblogs.com/EdwardLiu/p/5055920.html
Copyright © 2011-2022 走看看