leetcode刷题记录-1219. 黄金矿工 - 回溯算法

269 阅读2分钟

「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战

前言

今日的题目为中等,并且是首次接触回溯算法,对此的使用很不熟练,之后需要增强对回溯和深度广度优先搜索的练习

每日一题

今天的每日一题 1219. 黄金矿工,难度为中等

  • 你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。

  • 为了使收益最大化,矿工需要按以下规则来开采黄金:

  • 每当矿工进入一个单元,就会收集该单元格中的所有黄金。

  • 矿工每次可以从当前位置向上下左右四个方向走。

  • 每个单元格只能被开采(进入)一次。

  • 不得开采(进入)黄金数目为 0 的单元格。

  • 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。

示例 1:

输入:grid = [[0,6,0],[5,8,7],[0,9,0]]
输出:24
解释:
[[0,6,0],
 [5,8,7],
 [0,9,0]]
一种收集最多黄金的路线是:9 -> 8 -> 7

示例 2:

输入:grid = [[1,0,7],[2,0,6],[3,4,5],[0,3,0],[9,0,20]]
输出:28
解释:
[[1,0,7],
 [2,0,6],
 [3,4,5],
 [0,3,0],
 [9,0,20]]
一种收集最多黄金的路线是:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7

提示:

  • 1 <= grid.length, grid[i].length <= 15
  • 0 <= grid[i][j] <= 100
  • 最多 25 个单元格中有黄金。

题解

回溯算法

  1. 首先题目会给我们一个m*n的网格,只要格子中的数字大于0,就可以以这个格子为起点,首先我们来实现这个,只要遍历一遍整个数组,如果当前的值不为零,则将其当作起点进行判断,以这个点为起点的话,挖得的最大的黄金数是多少。
for (let i = 0; i < m; ++i) {
  for (let j = 0; j < n; ++j) {
    if (grid[i][j] !== 0) {
      maxGold();
    }
  }
}
  1. 接着我们定义一个maxGold函数用于判断当前位置为起点的最大黄金数量。函数传入当前的位置 i 和 j 以及当前位置的黄金数量glod方便相加计算
  2. 我们要通过回溯来判断获得的最大黄金数量,就需要通过递归的方式,判断每一个点位,它的上下左右是否超出边界,并且移动过的点位可以通过归0来禁止回退,这里我们定义一个数组用于判断边界:
this.boundary = [
   [-1, 0],
   [1, 0],
   [0, -1],
   [0, 1],
];

定义边界判断bx和by,只有当当前的bx和by都满足大于等于0且小于题目给的数组宽和长,才去判断下一步是否有数字,有的话递归重新进入下一格中。

for (let d = 0; d < 4; ++d) {
    const bx = x + this.boundary[d][0];
    const by = y + this.boundary[d][1];
    if (bx >= 0 && bx < m && by >= 0 && by < n && grid[bx][by] > 0) {
      maxGold(bx, by, gold);
    }
}
  1. 在每一次递归当中,我们在函数地下添加一个ans用于保存现在存在的最大黄金数:
 this.ans = Math.max(ans, gold);

这样就可以交给这句话去每次判断更新并且最后直接得出最大的黄金数。

  1. 最后将上面的所有步骤拼凑起来,就能够实现题目要求的函数了:
/**
 * @param {number[][]} grid
 * @return {number}
 */
var getMaximumGold = function (grid) {
  this.grid = grid;
  this.m = grid.length;
  this.n = grid[0].length;
  this.boundary = [
    [-1, 0],
    [1, 0],
    [0, -1],
    [0, 1],
  ];
  this.ans = 0;

  const maxGold = (x, y, gold) => {
    gold += grid[x][y];
    this.ans = Math.max(ans, gold);

    const rec = grid[x][y];
    grid[x][y] = 0;

    for (let d = 0; d < 4; ++d) {
      const bx = x + this.boundary[d][0];
      const by = y + this.boundary[d][1];
      if (bx >= 0 && bx < m && by >= 0 && by < n && grid[bx][by] > 0) {
        maxGold(bx, by, gold);
      }
    }

    grid[x][y] = rec;
  };
  for (let i = 0; i < m; ++i) {
    for (let j = 0; j < n; ++j) {
      if (grid[i][j] !== 0) {
        maxGold(i, j, 0);
      }
    }
  }
  return ans;
};

image.png