黄金矿工
难度:
标签:
题目描述
代码结果
运行时间: 441 ms, 内存: 16.1 MB
/*
* 使用Java Stream解决这个问题并不直接,因为Stream主要用于处理集合和数组的并行计算。
* 这里我们依旧使用DFS,但采用Java 8中的Optional等特性来优化代码。
*/
import java.util.Optional;
public class GoldMineStream {
private static final int[] directions = {0, 1, 0, -1, 0};
private int maxGold = 0;
public int getMaximumGold(int[][] grid) {
int m = grid.length, n = grid[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] > 0) {
dfs(grid, i, j, 0);
}
}
}
return maxGold;
}
private void dfs(int[][] grid, int x, int y, int currentGold) {
currentGold += grid[x][y];
maxGold = Math.max(maxGold, currentGold);
int original = grid[x][y];
grid[x][y] = 0;
Optional.of(directions).stream().flatMap(dir -> {
int nx = x + dir[0];
int ny = y + dir[1];
if (nx >= 0 && nx < grid.length && ny >= 0 && ny < grid[0].length && grid[nx][ny] > 0) {
dfs(grid, nx, ny, currentGold);
}
return Optional.empty().stream();
});
grid[x][y] = original;
}
}
解释
方法:
该题解使用了回溯法来解决问题。首先,它定义了一个递归函数backtrack来尝试所有可能的路径,并使用一个局部变量vis_local来记录已经访问过的单元格,以避免重复访问。函数backtrack接受当前位置(x, y)和当前收集到的黄金总量count作为参数,它会尝试向四个方向探索,并在探索后回溯。此外,题解中还使用了一个函数find_corner来优化搜索过程,该函数用于判断一个单元格是否是一个'角落',即最多只与两个有黄金的单元格相邻。如果一个单元格是角落,则可以从该单元格开始搜索,这样可以减少不必要的搜索次数。
时间复杂度:
O(4^(mn))
空间复杂度:
O(mn)
代码细节讲解
🦆
为什么在回溯算法中使用一个局部变量vis_local来记录访问状态,而不是修改原始的grid数组?
▷🦆
在find_corner函数中,判断一个单元格是否为角落的逻辑是否充分?是否有可能误判导致一些优秀的起点被忽略?
▷🦆
在backtrack函数中,如何保证在探索完四个方向后正确地回溯,恢复vis_local的状态?
▷