剑指offer day14 搜索与回溯算法(中等)

发表于 2022-04-12 971 字 5 min read

day14 题目:剑指 Offer 12. 矩阵中的路径剑指 Offer 13. 机器人的运动范围

知识点:数组、回溯、搜索,难度为中等、中等

学习计划链接:「剑指 Offer」 - 学习计划

题目知识点难度
剑指 Offer 12. 矩阵中的路径数组回溯矩阵中等
剑指 Offer 13. 机器人的运动范围深度优先搜索广度优先搜索中等

剑指 Offer 12. 矩阵中的路径

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

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

例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。

示例 1:

输入: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出: true

示例 2:

输入: board = [["a","b"],["c","d"]], word = "abcd"
输出: false

提示:

  • 1 <= board.length <= 200
  • 1 <= board[i].length <= 200
  • board 和 word 仅由大小写英文字母组成

注意: 本题与主站 79 题相同:https://leetcode-cn.com/problems/word-search/

思路

非常典型的深搜典型题,以矩阵中每个符合单词开头的元素作为起点开始搜。

/**
 * @param {character[][]} board
 * @param {string} word
 * @return {boolean}
 */
var exist = function (board, word) {
  function dfs(i, j, idx) {
    if (idx == word.length) return true; // 找到单词了
    if (i < 0 || i >= board.length || j < 0 || j >= board[0].length || board[i][j] == '#' || board[i][j] != word[idx])
      return false; // 越界或者不匹配
    board[i][j] = '#'; // 置为#,避免重复访问
    let flag = false;
    if (dfs(i + 1, j, idx + 1) || dfs(i - 1, j, idx + 1) || dfs(i, j + 1, idx + 1) || dfs(i, j - 1, idx + 1))
      // 四个方向试探
      flag = true;
    board[i][j] = word[idx]; // 恢复
    return flag;
  }
  for (let i = 0; i < board.length; ++i) {
    for (let j = 0; j < board[0].length; ++j) {
      if (board[i][j] === word[0]) if (dfs(i, j, 0)) return true;
    }
  }
  return false;
};

剑指 Offer 13. 机器人的运动范围

地上有一个 m 行 n 列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0]的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于 k 的格子。例如,当 k 为 18 时,机器人能够进入方格 [35, 37] ,因为 3+5+3+7=18。但它不能进入方格 [35, 38],因为 3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:

输入: m = 2, n = 3, k = 1
输出: 3

示例 2:

输入: m = 3, n = 1, k = 0
输出: 1

提示:

  • 1 <= n,m <= 100
  • 0 <= k <= 20

思路

广搜,注意搜索方向可以向右和向下就行了

/**
 * @param {number} m
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var movingCount = function (m, n, k) {
  function count(x) {
    if (x == 0) return 0;
    let sum = 0;
    while (x) {
      sum += x % 10;
      x = Math.floor(x / 10);
    }
    return sum;
  }

  let dx = [1, 0];
  let dy = [0, 1]; // 下 右
  let canVis = new Array(m).fill(0).map(() => new Array(n).fill(false));
  let vis = new Array(m).fill(0).map(() => new Array(n).fill(false));
  for (let i = 0; i < m; ++i) for (let j = 0; j < n; ++j) canVis[i][j] = count(i) + count(j) <= k;

  function judge(i, j) {
    if (i < 0 || i >= m || j < 0 || j >= n || !canVis[i][j] || vis[i][j]) return false;
    return true;
  }
  let q = [];
  let ans = 0;
  vis[0][0] = true;
  q.push([0, 0]);
  while (q.length) {
    let [x, y] = q.shift();
    ++ans;
    for (let i = 0; i < 2; ++i) {
      let nx = x + dx[i];
      let ny = y + dy[i];
      if (judge(nx, ny)) {
        vis[nx][ny] = true;
        q.push([nx, ny]);
      }
    }
  }
  return ans;
};