zoukankan      html  css  js  c++  java
  • leetcode 62. 不同路径-动态规划及优化,双100%

    62. 不同路径

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

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

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

    示例 1:

    输入: m = 3, n = 2
    输出: 3
    解释:
    从左上角开始,总共有 3 条路径可以到达右下角。
    1. 向右 -> 向右 -> 向下
    2. 向右 -> 向下 -> 向右
    3. 向下 -> 向右 -> 向右
    

    示例 2:

    输入: m = 7, n = 3
    输出: 28
    

    提示:

    • 1 <= m, n <= 100
    • 题目数据保证答案小于等于 2 * 10 ^ 9

    解题思路

    由于我们的目的是从左上角到右下角一共有多少种路径,那我们就定义 dp[i][j]的含义为:当机器人从左上角走到(i, j) 这个位置时,一共有 dp[i][j] 种路径。 那么,dp[m-1][n-1] 就是我们要的答案了。

    步骤

    找出关系数组元素间的关系式想象以下,机器人要怎么样才能到达 (i, j) 这个位置?由于机器人可以向下走或者向右走,所以有两种方式到达一种是从 (i-1, j) 这个位置走一步到达一种是从(i, j - 1) 这个位置走一步到达因为是计算所有可能的步骤,所以是把所有可能走的路径都加起来,所以关系式是 dp[i][j] = dp[i-1][j] + dp[i][j-1]
    找出初始值显然,当 dp[i][j] 中,如果 i 或者 j 有一个为 0,那么还能使用关系式吗?答是不能的,因为这个时候把 i - 1 或者 j - 1,就变成负数了,数组就会出问题了,所以我们的初始值是计算出所有的 dp[0][0….n-1] 和所有的 dp[0….m-1][0]
    这个还是非常容易计算的,相当于计算机图中的最上面一行和左边一列。因此初始值如下:
    dp[0][0…n-1] = 1; // 相当于最上面一行,机器人只能一直往左走
    dp[0…m-1][0] = 1; // 相当于最左面一列,机器人只能一直往下走

    class Solution
    {
    public:
        int uniquePaths(int m, int n)
        {
            if (m <= 0 || n <= 0)
            {
                return 0;
            }
            if (m == 1 || n == 1)
            {
                return 1;
            }
    
            vector<vector<int>> dp(m, vector<int>(n)); //创建大小为m*n的数组
            // 初始化
            for (int i = 0; i < m; i++)
            {
                dp[i][0] = 1;
            }
            for (int i = 0; i < n; i++)
            {
                dp[0][i] = 1;
            }
            // 推导出 dp[m-1][n-1]
            for (int i = 1; i < m; i++)
            {
                for (int j = 1; j < n; j++)
                {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
            return dp[m - 1][n - 1];
        }
    };
    

    优化

    根据公式 dp[i][j] = dp[i-1][j] + dp[i][j-1],我们可以知道,当我们要计算第 i 行的值时,除了会用到第 i - 1 行外,其他第 1 至 第 i-2 行的值我们都是不需要用到的,因为计算某一行的时候,依赖的是左一结果和上一结果,所以我们存一行的记录,只要这一行包含当前元素的左一结果和上一结果即可。我们只需要用一个一维的 dp[] 来保存一行的历史记录就可以了。然后在计算的过程中,不断着更新 dp[] 的值。
    所以在dp[n]这个数组里面,dp[0]...dp[j-1]是本一行的,dp[j]...dp[n]是上一行。

    代码

    class Solution {
    public:
        int uniquePaths(int m, int n) {
            if (m <= 0 || n <= 0)
            {
                return 0;
            }
            if (m == 1 || n == 1)
            {
                return 1;
            }
    
            vector<int> dp(n);
            // 初始化
            for (int i = 0; i < n; i++)
            {
                dp[i] = 1;
            }
            // 推导出 dp[m-1][n-1]
            for (int i = 1; i < m; i++)
            {
                // 第 i 行第 0 列的初始值
                dp[0] = 1;
                for (int j = 1; j < n; j++)
                {
                    dp[j] = dp[j - 1] + dp[j];
                }
            }
            return dp[n - 1];
        }
    };
    
  • 相关阅读:
    Bootstrap基础(七):按钮
    Bootstrap基础(六):表单
    Bootstrap基础(五):表格
    Bootstrap基础(四):代码
    Bootstrap基础(三):排版
    Bootstrap基础(二):网格系统
    Bootstrap基础(一):CSS 概览
    本人承接各种.Net网站制作,软件项目等业务。完美帮您定做
    iOS沙盒路径的查看和使用
    asp.net 源码坊4-6源码发布
  • 原文地址:https://www.cnblogs.com/flying_bat/p/12737777.html
Copyright © 2011-2022 走看看