剑指offer面试题13 机器人的运动范围

111 阅读4分钟

机器人的运动范围__牛客网 (nowcoder.com)

image.png

BFS(广度优先搜索)

image.png 这是一个使用动态规划方法解决“按数组中的元素和行走”问题的代码。下面是逐行代码解析:

  1. class Solution {:定义一个名为Solution的公共类。
  2. public int movingCount(int threshold, int rows, int cols) {:定义一个名为movingCount的公共方法,接收三个参数:阈值(表示数组中元素的和)、行数和列数。
  3. bool** isVisited = new bool*[rows];:创建一个二维布尔指针数组isVisited,用于记录是否已经走过。
  4. for (int i = 0; i < rows; i++) {:遍历行数组。
  5. isVisited[i] = new bool[cols];:为每一行分配一个布尔数组。
  6. for (int j = 0; j < cols; j++) {:遍历列数组。
  7. isVisited[i][j] = false;:初始化所有元素为未走过。
  8. }:结束列遍历。
  9. }:结束行遍历。
  10. int count = jude(threshold, rows, cols, 0, 0, isVisited);:调用jude方法,传入阈值、行数、列数、初始位置(0, 0)和isVisited数组,获取走过格子数。
  11. for (int i = 0; i < rows; i++) {:遍历行数组。
  12. delete[] isVisited[i];:释放每一行的内存。
  13. }:结束行遍历。
  14. delete[] isVisited;:释放二维指针数组。
  15. return count;:返回计算结果。

jude方法解析:

  1. int jude(int threshold, int rows, int cols, int i, int j, bool** isVisited) {:定义一个名为jude的递归方法,接收五个参数:阈值、行数、列数、初始位置(ij)和isVisited数组。
  2. if (i < 0 || j < 0 || i >= rows || j >= cols || isVisited[i][j] || nums(i) + nums(j) > threshold) {:判断当前位置是否合法,如果不合法则返回 0。
  3. isVisited[i][j] = true;:将当前位置标记为已走过。
  4. int count = jude(threshold, rows, cols, i - 1, j, isVisited) + jude(threshold, rows, cols, i + 1, j, isVisited) + jude(threshold, rows, cols, i, j - 1, isVisited) + jude(threshold, rows, cols, i, j + 1, isVisited) + 1;:递归调用jude方法,计算从当前位置向左、向右、向上和向下走的结果,并返回累加和。
  5. return count;:返回计算结果。 nums方法解析:
  6. int nums(int n) {:定义一个名为nums的公共方法,接收一个整数参数n
  7. int sum = 0;:初始化求和变量sum为 0。
  8. while (n > 0) {:使用do-while循环,当n不为 0 时执行以下操作。
  9. sum += n % 10;:将n的个位数加到sum中。
  10. }:结束循环。
  11. return sum;:返回计算结果。

注意点:

image.png

image.png





class Solution {
 public:
  int movingCount(int threshold, int rows, int cols) {
    //首先判空
    if (rows < 0 || cols < 0 || threshold < 0) return 0;
    //写一个布尔型的变量表示是否走过
    bool** isVisited = new bool*[rows];
    for (int i = 0; i < rows; i++) {
      isVisited[i] = new bool[cols];
      for (int j = 0; j < cols; j++) {
        isVisited[i][j] = false;
      }
    }
    //是否走过交给 jude 函数进行判断
    //每次递归的返回值给 count,count 记录走了多少个格子
    int count = jude(threshold, rows, cols, 0, 0, isVisited);
    //销毁
    for (int i = 0; i < rows; i++) {
      delete[] isVisited[i];
    }
    delete[] isVisited;
    return count;
  }

  int jude(int threshold, int rows, int cols, int i, int j, bool** isVisited) {
    //通过递归进行判断
    //如果上下左右都走过,返回 true,否则返回 false
    //递归结束条件:越界,全部走完了,还有坐标路径和大于阈值
    if (i < 0 || j < 0 || i >= rows || j >= cols || isVisited[i][j]==true ||
        nums(i) + nums(j) > threshold) {
      return 0;
    }
    //将当前位置标记为已经走过了,再递归调用走另一个方向。
    isVisited[i][j] = true;
    //递归调用走上下左右,把上下左右的看路径相加,再加上1(当前位置)
    int count = jude(threshold, rows, cols, i - 1, j, isVisited) +
                jude(threshold, rows, cols, i + 1, j, isVisited) +
                jude(threshold, rows, cols, i, j - 1, isVisited) +
                jude(threshold, rows, cols, i, j + 1, isVisited) +
                1;
    return count;
  }

  //判断是否能进入方格
  int nums(int n) {
    int sum = 0;
    while (n > 0) {
      sum += n % 10;
      n /= 10;
    }
    return sum;
  }
};

DFS(深度优先搜索)

image.png

image.png



class Solution {
 public:
  int movingCount(int threshold, int rows, int cols) {
    //首先判空
    if (rows < 0 || cols < 0 || threshold < 0) return 0;
    //写一个布尔型的变量表示是否走过
    bool** isVisited = new bool*[rows];
    for (int i = 0; i < rows; i++) {
      isVisited[i] = new bool[cols];
      for (int j = 0; j < cols; j++) {
        isVisited[i][j] = false;
      }
    }
    //是否走过交给 jude 函数进行判断
    //每次递归的返回值给 count,count 记录走了多少个格子
    int count = jude(threshold, rows, cols, 0, 0, isVisited);
    //销毁
    for (int i = 0; i < rows; i++) {
      delete[] isVisited[i];
    }
    delete[] isVisited;
    return count;
  }

  int jude(int threshold, int rows, int cols, int i, int j, bool** isVisited) {
    //通过递归进行判断
    //如果上下左右都走过,返回 true,否则返回 false
    //递归结束条件:越界,下标值 false[i][j] 与不相同,全部走完了
    if (i < 0 || j < 0 || i >= rows || j >= cols || isVisited[i][j]==true ||
        nums(i) + nums(j) > threshold) {
      return 0;
    }
    //将当前位置标记为已经走过了,再递归调用走另一个方向。
    isVisited[i][j] = true;
    //递归调用走上下左右,把上下左右的看路径相加,再加上本身这个 1
    int count = //jude(threshold, rows, cols, i - 1, j, isVisited) +
               jude(threshold, rows, cols, i + 1, j, isVisited) +
              //  jude(threshold, rows, cols, i, j - 1, isVisited) +
                jude(threshold, rows, cols, i, j + 1, isVisited) +
                1;
    return count;
  }

  //判断是否能进入方格
  int nums(int n) {
    int sum = 0;
    while (n > 0) {
      sum += n % 10;
      n /= 10;
    }
    return sum;
  }
};

image.png 画图解析:

image.png 假如从A点开始访问,DFS就是沿着一条道走下去,然后再走其他的道……。BFS就是图中先访问圈内的部分,然后再把圈放大继续访问……。