这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
leetcode-576-出界的路径数
[博客链接]
[题目描述]
给你一个大小为 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 <= 500 <= maxMove <= 500 <= startRow < m0 <= startColumn < n
Related Topics
示例 1:
输入:n = 4, preferences = [[1, 2, 3], [3, 2, 0], [3, 1, 0], [1, 2, 0]], pairs =
[[0, 1], [2, 3]]
输出:2
解释:
朋友 1 不开心,因为:
- 1 与 0 配对,但 1 与 3 的亲近程度比 1 与 0 高,且
- 3 与 1 的亲近程度比 3 与 2 高。
朋友 3 不开心,因为:
- 3 与 2 配对,但 3 与 1 的亲近程度比 3 与 2 高,且
- 1 与 3 的亲近程度比 1 与 0 高。
朋友 0 和 2 都是开心的。
示例 2:
输入:n = 2, preferences = [[1], [0]], pairs = [[1, 0]]
输出:0
解释:朋友 0 和 1 都开心。
示例 3:
输入:n = 4, preferences = [[1, 3, 2], [2, 3, 0], [1, 3, 0], [0, 2, 1]], pairs =
[[1, 3], [0, 2]]
输出:4
[题目链接]
[github地址]
[思路介绍]
思路一:暴力dfs+dp方程的来源分析
- 定义4个方向变量,每一次移动都有四个方向,判断出界的条件有4个
x + dir[i][0] >= ex || x + dir[i][0] < 0 || y + dir[i][1] >= ey || y + dir[i][1] < 0- dfs递归求解
- 定义计数器idx,不超过maxMove即满足条件
- 这样时间复杂度是O()
- 根据题目所给出的数据范围是一定会TLE的
class Solution{
int[][] dir = new int[][]{{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
int res = 0, max = 0, ex = 0, ey = 0;
public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
//定义四个移动方向
int mod = (int) 1e9 + 7, x = startRow, y = startColumn, idx = 0;
max = maxMove;
ex = m;
ey = n;
dfs(x, y, idx);
return res % mod;
}
public void dfs(int x, int y, int idx) {
//边界情况
if (idx >= max) {
return;
}
int temp = idx;
for (int i = 0; i < 4; i++) {
if (x + dir[i][0] >= ex || x + dir[i][0] < 0 || y + dir[i][1] >= ey || y + dir[i][1] < 0) {
res += 1;
continue;
}
dfs(x + dir[i][0], y + dir[i][1], temp + 1);
}
}
}
- 时间复杂度O()
- 空间复杂度O()
思路二:动态规划
- 根据思路一不难发现dfs递归方程一共有三个变量
- x, y, idx 分别表示
- x:横坐标
- y:纵坐标
- idx:移动步数
- 因此我们可以确定dp方程dp[idx][j][k]
- 表示使用idx步从起始位置**(x, y)** 移动到 (j, k) 的方案数量
- 初始化dp数组易得出dp[0][x][y] = 1
- 表示使用0步从起点移动到起点只有一种方案
- 其余状态的dp方程过程如下
- dp[idx+1][j][k] = dp[idx][j-1][k] + dp[idx][j+1][k] + dp[idx][j][k-1] + dp[idx][j][k+1];
- 上述dp方程更可以使用循环赋值的方式保证不漏
- 也就是通过每个dp[idx][j][k] 求得其下一步移动四个方向后的dp[idx+1][j+dir[0]][k+dir[1]]
- 这样方便计算
public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
int[][] dirs = new int[][]{{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
int x = startRow, y = startColumn, mod = (int) 1e9 + 7;
int res = 0;
int[][][] dp = new int[maxMove + 1][m][n];
//初始化
dp[0][x][y] = 1;
for (int i = 0; i < maxMove; i++) {
for (int j = 0; j < m; j++) {
for (int k = 0; k < n; k++) {
int cnt = dp[i][j][k];
if (cnt > 0) {
for (int[] dir : dirs
) {
int mx = j + dir[0], my = k + dir[1];
if (mx >= 0 && mx < m && my >= 0 && my < n) {
dp[i + 1][mx][my] = (dp[i + 1][mx][my] + cnt) % mod;
} else {
res = (res + cnt) % mod;
}
}
}
}
}
}
return res;
}
- 时间复杂度
- 空间复杂度
思路三:还是补充一下记忆化递归吧
public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
//定义四个移动方向
int x = startRow, y = startColumn, idx = 0;
max = maxMove;
ex = m;
ey = n;
return dfs(x, y, idx) % mod;
}
public int dfs(int x, int y, int idx) {
String key = x + "," + y + "," + idx;
if (map.containsKey(key)) {
return map.get(key);
}
//出界情况
if (idx <= max && (x < 0 || x == ex || y < 0 || y == ey)) {
map.put(key, 1);
return 1;
}
//到达不了边界情况
if (idx > max) {
map.put(key, 0);
return 0;
}
int temp = idx, ans = 0;
for (int i = 0; i < 4; i++) {
ans = (ans + dfs(x + dir[i][0], y + dir[i][1], temp + 1)) % mod;
}
map.put(key, ans);
return ans;
}
- 「TODO」周赛还未开始,晚上补题解