2684. 矩阵中移动的最大次数https://leetcode.cn/problems/maximum-number-of-moves-in-a-grid/description/?envType=daily-question&envId=2024-03-16这题刚看到想到的就是用深度优先遍历来做,结果超时了。仔细一看发现在移动单元格的时候永远都是向右的,也就是说不可能走到已经走过的单元格上。这说明每个子问题求解的时候不受前面已经走过的路径的影响。那么我们就可以给深度优先搜索加上一个备忘录,记录已经求解的子问题。此外甚至可以用动态规划来求解。
下面是带备忘录的递归(记忆化递归)的求解方法。
class Solution {
public:
int current_steps=0;
int max_steps=INT_MIN;
int maxMoves(vector<vector<int>>& grid) {
vector<vector<int>> mem(grid.size(), vector<int>(grid[0].size(), -1));
for (int i=0; i < grid.size(); ++i) {
dfs(grid, i, 0, INT_MIN, mem);
}
return max_steps - 1;
}
void dfs(vector<vector<int>>& grid, int x, int y, int pre, vector<vector<int>>& mem) {
if (x < 0 || x == grid.size() || y < 0 || y == grid[0].size() ||grid[x][y] <= pre) {
max_steps = max(current_steps, max_steps);
return;
}
if (mem[x][y] != -1) {
max_steps = max(max_steps, mem[x][y]);
return ;
}
current_steps += 1;
dfs(grid, x-1, y+1, grid[x][y], mem);
dfs(grid, x, y+1, grid[x][y], mem);
dfs(grid, x+1, y+1, grid[x][y], mem);
current_steps -= 1;
mem[x][y] = max_steps;
}
};
另外一种写法,跟上面的不同,上面的是深度优先遍历过程中记录已经走过的步数,并把经过当前点能达到的最大步数写在备忘录里。下面这种写法是记录从每个节点开始能移动多少步。两种写法代表两种不同的思路吧,但差别不大。
class Solution {
public:
int maxMoves(vector<vector<int>>& grid) {
vector<vector<int>> mem(grid.size(), vector<int>(grid[0].size(), -1));
function<int(int, int)> dfs = [&] (int x, int y) -> int {
if (mem[x][y] != -1) return mem[x][y];
int res = 0;
bool none_move = true;
if (x - 1 >= 0 && y + 1 < grid[0].size() && grid[x-1][y+1] > grid[x][y]){
res = max(res, dfs(x -1, y+1));
none_move = false;
}
if (y + 1 < grid[0].size() && grid[x][y+1] > grid[x][y]) {
res = max(res, dfs(x, y+1));
none_move = false;
}
if (x + 1 < grid.size() && y + 1 < grid[0].size() && grid[x+1][y+1] > grid[x][y]) {
res = max(res, dfs(x + 1, y + 1));
none_move = false;
}
if (none_move) {
mem[x][y] = 0;
return 0;
}
mem[x][y] = res + 1;
return mem[x][y];
};
int result = 0;
for (int i=0; i < grid.size(); ++i) {
result = max(dfs(i, 0), result);
}
return result;
}
};