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格子的路徑數目 } };