Java动态规划经典面试题1 (机器人走格子)

Java动态规划经典面试题1(机器人走格子)

题目2 机器人走格子

题目概述

image-20200827174823330

题目分析

这是一道经典的面试题,用的就是动态规划算法,我们求最值,获取所有情况这些算法题很多都是动态规划的范畴,首先我们按照解题思路一步步来

  • 最后一步

    当机器人走到最后一步的时候,其位置无非就是终点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

题目概述

image-20200827180444444

思想差不多我们重新审视一下边界条件

  • 障碍物出现在了边缘

image-20200827180837520

image-20200827181030526

  • 障碍物出现在了中间

image-20200827181346219

image-20200827181427152

原来的代码

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

力扣结果图

我们把数据都存进数组,然后再去数组查询,空间换时间的概念。

image-20200827184709299

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值