给你一个大小为 m x n 的网格和一个球。球的起始坐标为 [startRow, startColumn] 。你可以将球移到在四个方向上相邻的单元格内(可以穿过网格边界到达网格之外)。你 最多 可以移动 maxMove 次球。
给你五个整数 m、n、maxMove、startRow 以及 startColumn ,找出并返回可以将球移出边界的路径数量。因为答案可能非常大,返回对 109 + 7 取余 后的结果。
示例 1:
输入:m = 2, n = 2, maxMove = 2, startRow = 0, startColumn = 0
输出:6
示例 2:
输入:m = 1, n = 3, maxMove = 3, startRow = 0, startColumn = 1
输出:12
提示:
1 <= m, n <= 50
0 <= maxMove <= 50
0 <= startRow < m
0 <= startColumn < n
class Solution {
int mod = (int)1e9 + 7;
int m, n;
int[] dx = new int[]{-1, 0, 1, 0}, dy = new int[]{0, 1, 0, -1};
//暴力dfs会超时,所以需要记忆化搜索
int[][][] cache;
public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
this.m = m; this.n = n;
cache = new int[m + 1][n + 1][maxMove + 1];
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
for (int k = 0; k <= maxMove; ++k)
cache[i][j][k] = -1;
return dfs(startRow, startColumn, maxMove);
}
int dfs(int x, int y, int k) {
//说明到达了外面
if (x < 0 || x >= m || y < 0 || y >= n) return 1;
//没有步数直接返回0
if (k == 0) return 0;
//记忆化
if (cache[x][y][k] != -1) return cache[x][y][k];
//四个方向扩展
int sum = 0;
for (int i = 0; i < 4; ++i) {
sum += dfs(x + dx[i], y + dy[i], k - 1);
sum %= mod;
}
cache[x][y][k] = sum;
return sum;
}
}
dp
class Solution {
/**
f[i][j][k] : 当前位置是[i, j],在步数最多是k的情况下移出网格的路径书
考虑把维度缩小,用idx = i * m + j表示坐标
状态转移:f[i][j][k] = f[i - 1][j][k - 1] + f[i][j - 1][k - 1] + f[i + 1][j][k - 1] + f[i][j + 1][k -1]
初始化,把矩阵边缘都初始化为1, 不过需要注意矩阵顶点是有两条路径到外面的
*/
int m, n, maxMove;
int mod = (int)1e9 + 7;
int[] dx = new int[]{-1, 0, 1, 0}, dy = new int[]{0, 1, 0, -1};
int[][] f;
public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
this.m = m; this.n = n; this.maxMove = maxMove;
f = new int[m * n + 1][maxMove + 1];
//初始化
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
for (int k = 1; k <= maxMove; ++k) {
//注意k 是 从1开始, 因为在边缘必须还要移动一格
if (i == 0) add(i, j, k);
if (i == m - 1) add(i, j, k);
if (j == 0) add(i, j, k);
if (j == n - 1) add(i, j, k);
}
//dp过程,先从小到大枚举步数,因为我们依赖步数 - 1
for (int i = 1; i <= maxMove; ++i)
for (int idx = 0; idx < m * n; ++idx) {
int[] t = parse(idx);
int x = t[0], y = t[1];
for (int j = 0; j < 4; ++j) {
int a = x + dx[j], b = y + dy[j];
if (a < 0 || a >= m || b < 0 || b >= n) continue;
int nidx = get(a, b);
f[idx][i] += f[nidx][i - 1];
f[idx][i] %= mod;
}
}
return f[get(startRow, startColumn)][maxMove];
}
int get(int x, int y) {
return x * n + y;
}
int[] parse(int idx) {
return new int[]{idx / n, idx % n};
}
void add(int i, int j, int k) {
f[get(i, j)][k] ++;
}
}