[JavaScript 刷题] 树 - 单词搜索 II, leetcode 212

[JavaScript 刷题] 树 - 单词搜索 II, leetcode 212

github repo 地址: https://github.com/GoldenaArcher/js_leetcode,Github 的目录 大概 会更新的更勤快一些。

题目地址:212. 单词搜索 II

题目

如下:

Given an m x n board of characters and a list of strings words, return all words on the board.

Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

解题思路

这道题的前置题是 79. Word Search,79 主要用的技巧就是 backtracking,但是如果只用 backtracking 的话,这道题就会超时。

暴力解的时间复杂度为 O ( w × m × n × 4 l ) O(w \times m \times n \times 4^l) O(w×m×n×4l),其中 4 l 4^l 4l 是每个单词遍历所需时间, l l l 代表单词的平均长度; w w w 代表单词的数量。总体的理解就是说,每一次遍历 grid[row][col] 的时候都查找一下所有的单词,去看单词是否有可能包含在当前的单词搜索路径中。

Trie 简述在 前缀树 trie 中有提到,简单地说,使用前缀树可以将时间按复杂度从 O ( w × m × n × 4 l ) O(w \times m \times n \times 4^l) O(w×m×n×4l) 降到 O ( m × n × 4 l ) O(m \times n \times 4^l) O(m×n×4l),因为每次遍历的时候就可以查看当前单词是否存在于 trie 中,如果不在还可以提前中断遍历。

用之前画的 trie 举例,下面的 trie 由这个数组构成:['apart', 'app', 'ape', 'apathetical', 'apathy'].。

trie

当在一个 m × n m \times n m×n 的二维数组中搜索这些单词的时候,只需要遍历 trie 一次就能够判断当前单词是否存在于单词列表中,而不需要遍历整个数组。

便利的过程就是 79. Word Search 的核心算法:backtracking。

使用 JavaScript 解题

我不知道为什么 if (node.word) res.add(node.word); 这里直接返回了,这就导致一些单词找不到……

嗯……

还debug了很久,这个需要注意一下,如果 ad 找到了,还是需要继续寻找 add 的,直接返回就会中断搜索。

/**
 * @param {character[][]} board
 * @param {string[]} words
 * @return {string[]}
 */
class TreeNode {
    
    
  constructor(val) {
    
    
    this.val = val;
    this.children = [];
    this.word = null;
  }

  getIdx(ch) {
    
    
    return ch.charCodeAt(0) - "a".charCodeAt(0);
  }

  addChild(word) {
    
    
    let root = this;
    for (const ch of word) {
    
    
      const idx = this.getIdx(ch);
      if (!root.children[idx]) root.children[idx] = new TreeNode(ch);

      root = root.children[idx];
    }

    root.word = word;
  }

  isChild(ch) {
    
    
    const idx = this.getIdx(ch);
    return this.children[idx] !== undefined;
  }

  getChild(ch) {
    
    
    const idx = this.getIdx(ch);
    return this.children[idx];
  }
}

var findWords = function (board, words) {
    
    
  const root = new TreeNode(""),
    ROWS = board.length,
    COLS = board[0].length,
    res = new Set(),
    directions = [
      [0, 1],
      [0, -1],
      [1, 0],
      [-1, 0],
    ];

  for (const word of words) {
    
    
    root.addChild(word);
  }

  const dfs = (r, c, node, letter) => {
    
    
    if (
      r < 0 ||
      c < 0 ||
      r === ROWS ||
      c === COLS ||
      !board[r][c] ||
      !node.isChild(letter)
    )
      return;

    board[r][c] = "#";

    node = node.getChild(letter);

    if (node.word) res.add(node.word);

    for (const [ri, ci] of directions) {
    
    
      if (!board[r + ri]) continue;

      dfs(r + ri, c + ci, node, board[r + ri][c + ci]);
    }

    board[r][c] = letter;
  };

  for (let i = 0; i < ROWS; i++) {
    
    
    for (let j = 0; j < COLS; j++) dfs(i, j, root, board[i][j]);
  }

  return Array.from(res);
};

猜你喜欢

转载自blog.csdn.net/weixin_42938619/article/details/125761572
今日推荐