1. 程式人生 > >【Leetcode】【DP-二維陣列】 62. Unique Paths / 不同路徑

【Leetcode】【DP-二維陣列】 62. Unique Paths / 不同路徑

給一個形狀為m x n的矩陣,求從左上角到右下角的不同路徑的個數。行進時只能往右/下移動。


  • 方法一:使用二維陣列儲存每個位置的dp值

稍作畫圖分析即可得到dp式子:dp [i] [j] = dp [i-1] [j] + dp [i] [j-1]


(1)首先,可知若只能往下或往右走,則只能有一條路徑。可以先將第一行與第一列進行賦值,再通過迴圈計算其他格的dp值,防止 i-1 或 j-1 非法(當前i, j格沒有上一格/左一格)。注意二維vector的初始化方法。

        if(m == 1 || n == 1)   // 若 行/列 為1,則必定只有一條路徑
            return 1;
        vector<vector<int>> dp(m, vector<int>(n, 1));    // 二維vector的初始化方法
        for(int i=0; i<n; i++) {    // 先對第一行賦初值。實際在對dp初始化時已經為所有的值初始化為1
            dp[0][i] = 1;
        }
        for(int i=0; i<m; i++) {    // 對第一列
            dp[i][0] = 1;
        }

(2)根據dp [i] [j] = dp [i-1] [j] + dp [i] [j-1], 迴圈得到其他dp值。

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

最後再返回 dp [m-1] [n-1] ,即是走到右下角的路徑數。不要誤寫為dp [m] [n],會導致越界。


總程式碼:

class Solution {
public:
    int uniquePaths(int m, int n) {
        if(m == 1 || n == 1)                       
            return 1;
        vector<vector<int>> dp(m, vector<int>(n, 1));  // (1)初始狀態值
/* 以下內容可不用 for(int i=0; i<n; i++) { dp[0][i] = 1; } for(int i=0; i<m; i++) { dp[i][0] = 1; } */ for(int i=1; i<m; i++) {                    // (2)基於初始狀態值和dp公式,計算其他位置的值 for(int j=1; j<n; j++) { dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } return dp[m-1][n-1];                        // (3)返回右下角的dp值 } };
  • 方法二:優化記憶體空間,使用一維陣列儲存

每一處的位置僅與左側和上側相關,使用一個一維陣列dp,當前位置為dp[j],左側即為dp[j-1],上側即為dp[j](未更新dp[j]之前,這一位置即是上一行的j處)。


所以更新規則變為:dp[j] = dp[j-1] + dp[j],初始化為1。

總程式碼如下:

    int uniquePaths(int m, int n) {
        if(m == 1 || n == 1)
            return 1;
        vector<int> dp(n, 1);        // 使用一維陣列
        for(int i=1; i<m; i++) {        
            for(int j=1; j<n; j++) {    
                dp[j] = dp[j-1] + dp[j];    // 更新規則
            }
        }
        return dp[n-1];        // 返回最後一個位置即為右下角的位置
    }