• 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 }
  • 相关阅读:
    python实现git操作
    CentOS 安装R包 报错:internet routines cannot be loaded ,如何解决
    CentOS 6.8上安装指定版本的注释软件 VEP,release 93.4
    Anaconda3安装后在Pycharm中报错:ImportError: DLL load failed: 找不到指定的模块
    CentOS编译fastp 0.19.4 时报错/usr/bin/ld: cannot find -lz
    推荐一款非常好用的在线python编辑器——Colaboratory
    mac如何用quick look预览多个文件或者图片
    Pileup 格式详细说明
    CentOS 7 上安装 Django 2.2.4,解决报错:No module named ‘_sqlite3′
    Message: 'chromedriver' executable needs to be available in the path.
  • 原文地址:https://www.cnblogs.com/EdwardLiu/p/5055920.html
Copyright © 2020-2023  润新知