1. 程式人生 > 實用技巧 >62:不同路徑(C++)

62:不同路徑(C++)

題目地址:https://leetcode-cn.com/problems/unique-paths/

題目描述

一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記為“Start” )。機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為“Finish”)。問總共有多少條不同的路徑?

提示:

  • 1 <= m, n <= 100
  • 題目資料保證答案小於等於2 * 10 ^ 9

題目示例

示例1:

輸入: m = 3, n = 2
輸出: 3
解釋:
從左上角開始,總共有 3 條路徑可以到達右下角。
1. 向右 -> 向右 -> 向下


2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例2:

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

解題思路

分析題目可知,到達終點Finish,可以看作是終點的前一列或者前一行的格子,遞迴式具體可表示為arr[m][n]=arr[m-1][n]+arr[m][n-1]。知道有些同學看不明白,分享一個圖,如下

思路1:遞迴。對題目給的問題採用自頂向下的思想,拆分為若干子問題求解,但存在子問題的重複求解問題,時間複雜度O(2^mn);

思路2:記憶化搜尋。該方法是對遞迴的方法進行優化,使用陣列儲存已經求解過的路徑避免重複,時間複雜度O(nn),空間複雜度O(mn);

思路3:動態規劃。將原問題拆分為若干子問題,然後對每個子問題進行求解,並將結果進行儲存,從而避免了子問題的重複求解,時間複雜度O(mn),空間複雜度O(mn)。在這裡,我們使用二維陣列dp來儲存最終結果,其中dp[i][j]表示從起點(0,0)走到(i,j)的路徑數。根據題目可知,機器人只能向下或者向右,所以dp[i][j]的值就等於第i行第j列這個格子上面的那個格子的路徑數加上左邊那個格子的路徑數,即狀態轉移方程為dp[i][j]=dp[i-1][j]+dp[i][j-1],因為這兩個格子都可以走到第i行第j列的這個格子。

思路4:對思路3進行優化,主要是優化空間複雜度,因為在思路3中dp陣列儲存了所有格子的路徑資訊,我們可以使用一維陣列dp來儲存最終結果,即當前行格子的資訊,其中dp[j]=dp[j]+dp[j-1]為遞迴表示式。通俗講,也就是將每一行當作一個動態規劃處理,第一行初始化為全1,即路徑數為dp[0]=1,然後dp[1]為第二行路徑數,即j=1時的路徑數,而dp[1]等於上一行數加上當前行元素的值,即dp[1]=dp[0]+dp[1]=2,j=2時,dp[2]=上一行元素的值dp[2]+dp[2-1]=1+2=3,以此類推,可得dp[j]=dp[j]+dp[j-1]。

相似題目還有63、980。

程式原始碼

思路1

class Solution {
public:
    int uniquePaths(int m, int n) {
        if(m <= 0 || n <= 0) return 0;
        if(m == 1 && n == 1) return 1;
        return uniquePaths(m - 1, n) + uniquePaths(m, n - 1);
    }
};

思路2

class Solution {
public:
    int arr[101][101] = {0};
    int uniquePaths(int m, int n) {
        if(m <= 0 || n <= 0) return 0;
        if(m == 1 && n == 1) return 1;
        if(arr[m][n] > 0) return arr[m][n];
        arr[m - 1][n] = uniquePaths(m - 1, n);
        arr[m][n - 1] = uniquePaths(m, n - 1);
        arr[m][n] = uniquePaths(m - 1, n) + uniquePaths(m, n - 1);
        return arr[m][n];
    }
};

思路3

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for(int i = 0; i < m; i++) 
        {
            dp[i][0] = 1; //初始化第一列路徑
        }
        for(int j = 0; j < n; j++)
        {
            dp[0][j] = 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]; //到達Finish格子的路徑數目
    }
};

空間複雜度優化

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<int> dp(n, 1);
        for(int i = 1; i < m; i++)
        {
            for(int j = 1; j < n; j++)
            {
                dp[j] += dp[j - 1]; //狀態轉移方程
            }
        }
        return dp[n - 1]; //到達Finish格子的路徑數目
    }
};

參考文章

https://leetcode-cn.com/problems/unique-paths/solution/java-jian-dan-ming-liao-de-dong-tai-gui-hua-qiu-ji/