Java动态规划经典面试题1(机器人走格子)
题目2 机器人走格子
题目概述
题目分析
这是一道经典的面试题,用的就是动态规划算法,我们求最值,获取所有情况这些算法题很多都是动态规划的范畴,首先我们按照解题思路一步步来
-
最后一步
当机器人走到最后一步的时候,其位置无非就是终点Finish的上面或者左边,所以我们到达终点
(m-1,n-1)
的路径数等于到达(m-2,n-1)(m-1,n-2)
-
状态方程
显而易见:
F(m,n)=F(m-1,n)+F(m,n-1)
-
起始条件
如果网格的长度或者宽度为0,那么这个网格就不存在了,0钟可能的路径。
-
边界值
如果
F(m,n)=F(m-1,n)+F(m,n-1)
中m等于0或者n等于0,那么我们不应该使用这个公式计算,因为显而易见,m=0或者n=0只有一条路径
代码实现
class Solution {
public int uniquePaths(int m, int n) {
//边缘条件判断
if(m==0 || n==0){
return 0;
}
//创建一个二维数组用于存放走到每一格的可能路径
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
//如果是边界,则等于1
if (i == 0 || j == 0)
dp[i][j] = 1;
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
测试用例
m=0,n=1
m=1,n=9
m=3,n=3
测试结果
0
1
6
题目2机器人走格子2
题目概述
思想差不多我们重新审视一下边界条件
- 障碍物出现在了边缘
- 障碍物出现在了中间
原来的代码
class Solution {
public int uniquePaths(int m, int n) {
//边缘条件判断
if(m==0 || n==0){
return 0;
}
//创建一个二维数组用于存放走到每一格的可能路径
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
//如果是边界,则等于1
if (i == 0 || j == 0)
dp[i][j] = 1;
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
新的代码模板
由于条件变了,给出了一个二维数组,如果数组的值为1,说明这个是个障碍物,为0表示通畅,可能没有障碍物,我们先把原来的代码移植过来。
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
}
}
代码移植
class Solution {
public int uniquePaths(int[][] obstacleGrid) {
//边缘条件判断
if(obstacleGrid.length==0 || obstacleGrid[0].length==0){
return 0;
}
int m=obstacleGrid.length;
int n=obstacleGrid[0].length;
//创建一个二维数组用于存放走到每一格的可能路径
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
//如果是边界,则等于1
if (i == 0 || j == 0)
dp[i][j] = 1;
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
根据之前的条件判断,我们应该去除掉以下条件
- 格子的左边为障碍物,格子的上面为障碍物
- 边界不再是如果
i == 0 || j == 0
就返回1,而是判断i的左边是否有障碍物,j的上边是否有障碍物
边缘的判断比较简单,我们可以先第一次遍历判断边缘障碍物,第二次再判断中间障碍物
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
//边缘条件判断
if (obstacleGrid.length == 0 || obstacleGrid[0].length == 0) {
return 0;
}
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
//创建一个二维数组用于存放走到每一格的可能路径
int[][] dp = new int[m][n];
//先判断边界障碍物
for (int i = 0; i < m; i++) {
if (obstacleGrid[i][0] == 1) {
break;
} else {
dp[i][0] = 1;
}
}
for (int j = 0; j < n; j++) {
if (obstacleGrid[0][j] == 1) {
break;
} else {
dp[0][j] = 1;
}
}
//判断中间障碍物
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
//这个点就是障碍物
if (obstacleGrid[i][j] == 1) {
continue;
}
//这个点在障碍物的左边
if (obstacleGrid[i - 1][j] == 1) {
dp[i][j] = dp[i][j - 1];
}
//这个点在障碍物的下面
else if (obstacleGrid[i][j - 1] == 1) {
dp[i][j] = dp[i - 1][j];
}
//附近没有障碍物
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
测试用例
{0, 0, 0}
{0, 0, 0}
{0, 0, 0}
{0, 0, 0}
{0, 1, 0}
{0, 0, 0}
{0, 1, 0}
{0, 1, 0}
{0, 0, 0}
{0, 1, 0}
{0, 1, 0}
{0, 1, 0}
运行结果
6
2
1
0
力扣结果图
我们把数据都存进数组,然后再去数组查询,空间换时间的概念。