这类问题都是DP的简单用法:
相关算法:
P1002-过河卒:https://blog.csdn.net/qq_28033719/article/details/106261183
Unique Paths I
问题:
难度:easy
文章链接:https://blog.csdn.net/qq_28033719/article/details/107033638
Unique Paths II
问题:
难度:medium
说明:
输入一个二维数组 int[][] ,机器人只会往右往左走,然后多了石头,机器人不能通过石头,0 代表没有石头,1 代表有石头。
题目连接:https://leetcode.com/problems/unique-paths-ii/
输入案例:
Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
我的代码:
其实也是和过河卒一样,过河卒好歹是一个马,这只是个石头更加简单。
二维数组做法:
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int x = obstacleGrid.length;
int y = obstacleGrid[0].length;
int[][] dp = new int[x][y];
for(int i = 0;i < x;i ++)
if(obstacleGrid[i][0] != 1) dp[i][0] = 1;
else break;
for(int i = 0;i < y;i ++)
if(obstacleGrid[0][i] != 1) dp[0][i] = 1;
else break;
for(int i = 1;i < x;i ++)
for(int j = 1;j < y;j ++)
if(obstacleGrid[i][j] != 1) dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
return dp[x - 1][y - 1];
}
}
改成一维数组,其实也就是减少空间复杂度:
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int x = obstacleGrid.length;
int y = obstacleGrid[0].length;
int[] dp = new int[y];
for(int i = 0;i < y;i ++)
if(obstacleGrid[0][i] != 1) dp[i] = 1;
else break;
boolean open = obstacleGrid[0][0] != 1; // 做 X 轴石头标记
for(int i = 1;i < x;i ++) {
if(open) dp[0] = (open = obstacleGrid[i][0] != 1) ? 1 : 0;
for(int j = 1;j < y;j ++)
dp[j] = obstacleGrid[i][j] != 1 ? dp[j] + dp[j - 1] : 0;
}
return dp[y - 1];
}
}
也可以用输入给出来的那个数组,区分下,石头 路径 两个数量区别就行,尤其是开头和开头边界的数字
class Solution {
public int uniquePathsWithObstacles(int[][] ob) {
int x = ob.length;
int y = ob[0].length;
boolean block = ob[0][0] == 1; // 要区分开头是否阻塞了
for(int i = 0;i < x;i ++)
if(ob[i][0] != 1) ob[i][0] = 1;
else
for(;i < x;i ++) ob[i][0] = 0; // 注意边界的阻塞是全部
for(int i = 1;i < y;i ++)
if(!block && ob[0][i] != 1) ob[0][i] = 1;
else
for(;i < y;i ++) ob[0][i] = 0; // 注意边界的阻塞是全部
for(int i = 1;i < x;i ++)
for(int j = 1;j < y;j ++)
ob[i][j] = ob[i][j] != 1 ? ob[i - 1][j] + ob[i][j - 1] : 0;
return ob[x - 1][y - 1];
}
}
Unique Paths III
问题:
难度:hard
说明:
输入一个二维数组 int[][] ,机器人能够上下左右行动,然后-1表示不能走,1 表示开始位置, 2表示结束位置,机器人要把地图为 0 的地方走一遍,返回多少种走法。
题目连接:https://leetcode.com/problems/unique-paths-iii/
输入范围:
1 <= grid.length * grid[0].length <= 20
输入案例:
Example 1:
Input: [[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
Output: 2
Explanation: We have the following two paths:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)
Example 2:
Input: [[1,0,0,0],[0,0,0,0],[0,0,0,2]]
Output: 4
Explanation: We have the following four paths:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)
3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)
4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)
Example 3:
Input: [[0,1],[2,0]]
Output: 0
Explanation:
There is no path that walks over every empty square exactly once.
Note that the starting and ending square can be anywhere in the grid.
我的代码:
这个的话看题目看了好久,原来要全部 0 都走一遍,怪不得结果解析那么复杂。
具体还是做 dp 不过是 dfs 做法,幸好输入面积 20 以内,所以不会太耗时。
class Solution {
private static int x = 0;
private static int y = 0;
private static int count = 0;
public int uniquePathsIII(int[][] grid) {
count = 1;
x = grid.length;
y = grid[0].length;
int bi = 0, bj = 0;
for(int i = 0;i < x;i ++) // 统计需要浏览的 0 数量
for(int j = 0;j < y;j ++) if(grid[i][j] == 0) count ++;
A:for(; bi < x; bi ++) // 找开始
for(bj = 0; bj < y; bj ++) if(grid[bi][bj] == 1) break A;
return recurtion(bi, bj, grid, 0);
}
public int recurtion(int bi, int bj, int[][] grid, int c) {
if(!(bi < 0 || bi == x || bj < 0 || bj == y)) {
if(grid[bi][bj] == 0 || grid[bi][bj] == 1) {
grid[bi][bj] = 5; // 当前表示已经浏览过标记
int cc = c + 1;
int res = recurtion(bi - 1, bj, grid, cc)
+ recurtion(bi + 1, bj, grid, cc)
+ recurtion(bi, bj - 1, grid, cc)
+ recurtion(bi, bj + 1, grid, cc);
grid[bi][bj] = 0; // 退出浏览重置 0
return res;
} else if(grid[bi][bj] == 2 && c == count) return 1; // 到达终点并且全部 0 浏览
} return 0;
}
}