友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

212. 单词搜索 II

给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words返回所有二维网格上的单词

单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例 1:

0212 01
输入:board = [["o","a","a","n"],
              ["e","t","a","e"],
              ["i","h","k","r"],
              ["i","f","l","v"]],
     words = ["oath","pea","eat","rain"]
输出:["eat","oath"]

示例 2:

0212 02
输入:board = [["a","b"],
              ["c","d"]],
     words = ["abcb"]
输出:[]

提示:

  • m == board.length

  • n == board[i].length

  • 1 <= m, n <= 12

  • board[i][j] 是一个小写英文字母

  • 1 <= words.length <= 3 * 104

  • 1 <= words[i].length <= 10

  • words[i] 由小写英文字母组成

  • words 中的所有字符串互不相同

思路分析

回溯:先根据首字母对单词进行分类,再遍历矩阵,找出首字母对应的坐标点。再对单词列表和坐标点进行回溯匹配。通过 43 / 65 个测试用例,后超时!

利用前缀树+回溯,可以避免重复判断单词相同的前缀部分,可以节省大量的计算。

  • 一刷

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
 * 回溯+前缀树
 * <p>
 * 优化前,利用回溯,通过 43 / 65 个测试用例。超时!
 *
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-06-12 22:53:03
 */
int[][] options = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

public List<String> findWords(char[][] board, String[] words) {
  Trie trie = new Trie();
  for (String word : words) {
    trie.insert(word);
  }
  Set<String> result = new HashSet<>();
  for (int r = 0; r < board.length; r++) {
    for (int c = 0; c < board[r].length; c++) {
      dfs(board, r, c, trie, result);
    }
  }
  return new ArrayList<>(result);
}

private void dfs(char[][] board, int row, int col,
                 Trie trie, Set<String> result) {
  if (row < 0 || row >= board.length
    || col < 0 || col >= board[0].length) {
    return;
  }
  char letter = board[row][col];
  if (!trie.containsLetter(letter)) {
    return;
  }
  trie = trie.search(letter);
  if (trie.word != null) {
    result.add(trie.word);
  }
  board[row][col] = '#';
  for (int[] option : options) {
    int r = row + option[0];
    int c = col + option[1];
    dfs(board, r, c, trie, result);
  }
  board[row][col] = letter;
}

public static class Trie {
  Trie[] children = new Trie[26];
  String word;

  public void insert(String word) {
    Trie curr = this;
    for (int i = 0; i < word.length(); i++) {
      char c = word.charAt(i);
      if (curr.children[c - 'a'] == null) {
        curr.children[c - 'a'] = new Trie();
      }
      curr = curr.children[c - 'a'];
    }
    curr.word = word;
  }

  public boolean containsLetter(char letter) {
    int idx = letter - 'a';
    if (idx < 0 || idx >= children.length) {
      return false;
    }
    return children[idx] != null;
  }

  public Trie search(char letter) {
    return children[letter - 'a'];
  }
}