前端算法面试必刷题系列[32]

274 阅读3分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

56. 单词搜索 (word-search)

标签

  • DFS + 回溯
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个二维网格和一个单词,找出该单词是否存在于网格中。其实就是找个字符路径

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

示例:

board =
[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]

board =
[
  ['A','B','C','E'],
  ['S','F','C',('S')],
  ['A','D',('E'),('E')] => SEE => true
]

给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false

相关知识

组合问题,可以用回溯法:如果不了解,请移步这篇 回溯思想

非常类似的问题这个是之前的问题,非常的类似。

基本思路

  1. 我觉的这题看下面的代码注释已经非常清晰明了,重点在于对四个方向上的DFS。
  2. 答疑几个点:
  • visited 数组作用,记录下已经访问过的位置,以免路径重合
  • 判断走的步骤之后是否越界是本题的边界条件,说明是在内部走动,形成路径。
  • 深刻理解 DFS + 回溯 类型的问题之后,你会类比之前好多题做到触类旁通。

写法实现

var exist = function(board, word) {
  // 获取矩阵行、列数 和字符串 length
  const [row, col, wordLen] = [board.length, board[0].length, word.length]
  // 取四个方向上走的方式 (i, j)坐标 往上走就是 i - 1 =>对应 [-1, 0]
  // 右 左 上 下
  const stepDicts = [[0, 1], [0, -1], [1, 0], [-1, 0]]
  // 声明已经访问过的路径,初始化所有元素为 false (可以理解为之前问题的 curUsed)
  const visited = new Array(row).fill(0).map(it => new Array(col).fill(false));

  // 下面我们回顾 DFS ,搜索正确路径
  let dfs = (i, j, curIndex) => {
    // 如果当前位置正是需要搜的当前元素,且 curIndex已经是需要找的最后一个元素,直接返回 true
    if (board[i][j] === word.charAt(curIndex) && curIndex === wordLen - 1) {
      return true
    }
    // 如果当前位置不等于我们需要搜的当前串的 curIndex 的元素,返回false
    if (board[i][j] !== word.charAt(curIndex)) {
      return false
    }
    // 走到这步之后该位置存入visited,表示已经访问过,要不绕圈回到原点就有问题了
    visited[i][j] = true
    let res = false;

    // 分别往4个方向上试
    for (const [dx, dy] of stepDicts) {
      // 新的 i, j 就是往各自方向上加
      let newi = i + dx, newj = j + dy;
      // 这四个方向走完之后,还在范围之内,没有越出边界
      if (newi >= 0 && newi < row && newj >= 0 && newj < col) {
        // 而且并不是之前走过的路径
        if (!visited[newi][newj]) {
          // 那么我们就继续往下走一步,进行递归
          if (dfs(newi, newj, curIndex + 1)) {
            res = true;
            break;
          }
        }
      }
    }
    // 回溯一步
    visited[i][j] = false;
    return res;
  }

  // 遍历这个二维数组,寻找起始点,有起始点的话进行DFS
  for (let i = 0; i < row; i++) {
    for (let j = 0; j < col; j++) {
      // 位置元素是起始点元素
      if (board[i][j] === word[0] && dfs(i, j, 0)) {
        return true
      }
    }
  }

  return false

};

let board = [
  ["A","B","C","E"],
  ["S","F","C","S"],
  ["A","D","E","E"]]

console.log(exist(board, 'SEE'))

另外向大家着重推荐下这位大哥的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考