算法29:不同路径问题(力扣62和63题)--针对算法28进行扩展

文章讲述了在一个给定大小的网格中,机器人从左上角到右下角的不同路径数量计算,包括基础动态规划解决方案以及空间复杂度的优化。讨论了有无障碍物时的情况,并提供了相应的代码实现。
摘要由CSDN通过智能技术生成

题目:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

分析:

假设为3行2列的二维数组

1. 向右---向下---向下

2. 向下---向下---向右

3. 向下--向右---向下

可以推导

1. 一直向右和一直向下,每种走法只有1种走法,没有其他可以旋转的空间。因此

11
12
1

2 、那么到达dp[1][1] 的走法就是 1 + 1 = 2;

3. 那么到达右下角dp[2][1] 就是 2 + 1 = 3; 即3种走法

分析2:

假设有3行7列

1. 按行走,只有1种走法

2、按列走,只有一种走法,可得

1111111
1
1

那么dp[1][1] 就是 dp[0][1] + dp[1][0] 即 1+ 1 = 2;依次类推可得

1111111
1234567
1

第三行还是按照这种方式推导,可得

1111111
1234567
13610152128

因此,针对3行7列的二维数组,可得28种走法

代码实现:

public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];

        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[0][col] = 1;
        }

        //第一列都为1
        for (int row = 0; row < m; row++) {
            dp[row][0] = 1;
        }

        for (int row = 1; row < m; row++) {
            for(int col = 1; col < n; col++) {
                dp[row][col] = dp[row][col - 1] + dp[row - 1][col];
            }
        }

        return dp[m-1][n-1];
    }

还是一样的问题,以上代码的时间复杂度为O(m*n), 空间复杂度也为O(m*n). 如果100行100列的二维数组,将浪费100*100的空间复杂度。

空间压缩进行优化:

 public int uniquePaths2(int m, int n) {

        int[] dp = new int[n];
        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[col] = 1;
        }


        for (int row = 1; row < m; row++) {
            dp[0] = 1;
            for (int col = 1; col < n; col++) {
                dp[col] = dp[col -1] + dp[col];
            }
        }

        return dp[n -1];
    }

完整代码:

package code03.动态规划_07.lesson4;

//力扣62题
// https://leetcode.cn/problems/unique-paths/description/
public class DiffPathSum_02 {

    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];

        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[0][col] = 1;
        }

        //第一列都为1
        for (int row = 0; row < m; row++) {
            dp[row][0] = 1;
        }

        for (int row = 1; row < m; row++) {
            for(int col = 1; col < n; col++) {
                dp[row][col] = dp[row][col - 1] + dp[row - 1][col];
            }
        }

        return dp[m-1][n-1];
    }

    public int uniquePaths2(int m, int n) {

        int[] dp = new int[n];
        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[col] = 1;
        }


        for (int row = 1; row < m; row++) {
            dp[0] = 1;
            for (int col = 1; col < n; col++) {
                dp[col] = dp[col -1] + dp[col];
            }
        }

        return dp[n -1];
    }
}

力扣测试通过:

题目:力扣63题: 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

分析:

1. 这一题其实跟上面一体解法相同,唯一的不同之处是有障碍物。

2. 第一行和第一列遇到障碍物,那么后面的路都走不通而已

3. 后面的推导,当前方格为障碍物,设置0代表走不通;如果不为0,则按照原有逻辑进行推导即可

完整代码:

package code03.动态规划_07.lesson4;

//力扣63题
// https://leetcode.cn/problems/unique-paths-ii/description/
public class DiffPathSum_03 {


    //时间复杂度 O(m*n), 空间复杂度 O(m*n)
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;

        //obstacleGrid[0][0] == 1 代表左上角第一个就是障碍物
        //obstacleGrid[m-1][n-1] == 1 代表右下角最后一个是障碍物
        if (obstacleGrid == null
                || obstacleGrid.length == 0
                || obstacleGrid[0][0] == 1
                || obstacleGrid[m-1][n-1] == 1) {
            return 0;
        }

        int[][] dp = new int[m][n];

        //处理第一行
        dp[0][0] = 1;
        for (int col = 1; col < n; col++) {
            //如果当前列为1, 或者前一列为0. 代表遇到障碍物。后面路走不通,全部变为0
            if (obstacleGrid[0][col] == 1 || dp[0][col -1] == 0) {
                dp[0][col] = 0;
            } else {
                //第一行只有1条路
                dp[0][col] = 1;
            }
        }

        //处理第一列
        for (int row = 1; row < m; row++) {
            //如果当前列为1, 或者上一列为0. 代表遇到障碍物。后面路走不通,全部变为0
            if (obstacleGrid[row][0] == 1 || dp[row-1][0] == 0) {
                dp[row][0] = 0;
            } else {
                //第一行只有1条路
                dp[row][0] = 1;
            }
        }

        for (int row = 1; row < m; row++) {
            for(int col = 1; col < n; col++) {
                //如果当前列有障碍物,此条路走不通。当前列的值变为0
                //否则,按照原有的逻辑进行计算
                dp[row][col] = obstacleGrid[row][col] == 1 ? 0: dp[row][col - 1] + dp[row - 1][col];
            }
        }

        return dp[m-1][n-1];
    }

    //空间压缩
    //时间复杂度 O(m*n), 空间复杂度 O(n)
    public int uniquePathsWithObstacles2(int[][] obstacleGrid) {

        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;

        //obstacleGrid[0][0] == 1 代表左上角第一个就是障碍物
        //obstacleGrid[m-1][n-1] == 1 代表右下角最后一个是障碍物
        if (obstacleGrid == null
                || obstacleGrid.length == 0
                || obstacleGrid[0][0] == 1
                || obstacleGrid[m-1][n-1] == 1) {
            return 0;
        }

        int[] dp = new int[n];
        //处理第一行
        dp[0] = 1;
        for (int col = 1; col < n; col++) {
            //如果当前列为1, 或者前一列为0. 代表遇到障碍物。后面路走不通,全部变为0
            if (obstacleGrid[0][col] == 1 || dp[col -1] == 0) {
                dp[col] = 0;
            } else {
                //第一行只有1条路
                dp[col] = 1;
            }
        }

        for (int row = 1; row < m; row++) {
            //当前列为障碍物或者上一列为障碍物,都走不通。
            dp[0] =  (obstacleGrid[row][0] == 1 || dp[0] == 0) ? 0 : 1;

            for(int col = 1; col < n; col++) {
                //如果当前列有障碍物,此条路走不通。当前列的值变为0
                //否则,按照原有的逻辑进行计算
                dp[col] = obstacleGrid[row][col] == 1 ? 0 : dp[col -1] + dp[col];
            }
        }

        return dp[n-1];
    }

    public static void main(String[] args) {
        DiffPathSum_03 test = new DiffPathSum_03();

        int[][] arr = {
                {0, 0, 0},
                {0, 1, 0},
                {0, 0, 0}
        };

        System.out.println(test.uniquePathsWithObstacles2(arr));
    }
}

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值