leetcode 62. 不同路径-动态规划及优化,双100%

老和山下的小学童 2020-04-20

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];
    }
};

相关推荐