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];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章