唯一路徑個數(shù)從遞歸到迭代

唯一路徑個數(shù)從遞歸到迭代

標簽(空格分隔): algorithm


唯一路徑個數(shù)

  • 唯一路徑個數(shù),題目大意,給定一個m \times n的矩陣,一個機器人位于左上角[1,1]的位置,目標是到達右下角[m,n]的位置,從左上角到右下角的方式是,機器人所在位置,每次可以向左或者向下移動一步,問從左上角到右下角有多少條唯一的路徑?

方法一:遞歸

  • 直觀想法,右下角為[m,n],那么如果到達這個位置,有兩個選擇,一個是從[m-1,n]向下一步,一個是從[m,n-1]向右一步。
  • 那么假設f(m,n)表示從左上角到達右下角的路徑數(shù),那么依據(jù)上面分析可以得到f(m,n) = f(m-1,n) + f(m,n-1)
  • 最基本情況是
  • 1、n=1 則返回f(m,1)=1
  • 2、m=1 則返回f(1,n)=1
    int uniquePaths(int m, int n) { return dfs(m, n); }
    int dfs(int m, int n) {
        if (m == 1 || n == 1) {
            return 1;
        }
        return dfs(m - 1, n) + dfs(m, n - 1);
    }
  • 時間復雜度:T(n) = O(x^n),x \in (1,2)。
  • 空間復雜度:函數(shù)調(diào)用O(m*n)

方法二:轉化為備忘錄遞歸

  • 上述方式存在子問題重復計算的情況,例如計算f(m,n),需要計算 f(m,n-1),f(m-1,n),計算f(m-1,n)的時候,還是需要計算f(m-1,n-1),計算f(m,n-1)的時候也需要計算f(m-1,n-1),可以發(fā)現(xiàn)非常多的子問題需要重新計算,我們用map,也可以用數(shù)組,來緩存已經(jīng)計算完的數(shù)據(jù)。對于已經(jīng)獲取的數(shù)據(jù)直接返回結果。
  • 對于已經(jīng)計算出來的符號排列結果用map來保存,例如map[2-3]=3,下次計算f(2,3)的時候可以直接使用
    unordered_map<string, int> cache;
    int uniquePaths(int m, int n) {
        return memo(m, n);
        return dfs(m, n);
    }
    int memo(int m, int n) {
        if (m == 1 || n == 1) {
            return 1;
        }
        auto key = getkey(m, n);
        if (cache.find(key) != cache.end()) {
            return cache[key];
        }
        auto x = memo(m - 1, n) + memo(m, n - 1);
        cache[key] = x;
        return x;
    }

    string getkey(int m, int n) {
        return to_string(m) + "_" + to_string(n);
    }
  • 時間復雜度:O(m*n)
  • 空間復雜度:O(m*n)

方法三:唯一路徑個數(shù)(轉化為迭代計算)

  • 從第二步,能看出,我們可以從基本情況(小規(guī)模的問題),來推導更為大的規(guī)模。
  • 假設f(m,n)表示矩陣m*n的唯一路徑個數(shù),依據(jù)上面的分析可以獲得,f(m,n) = f(m-1,n) + f(m,n-1)。
  • 基本情況:f(1,n) =1 ,f(m,1) = 1

f(m,n) = f(m-1,n) + f(m,n-1)

    int uniquePaths(int m, int n) {
        return dyp(m, n);
    }
    int dyp(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];
    }
  • 時間復雜度:O(m*n)
  • 空間復雜度:O(m*n)

空間優(yōu)化

  • 迭代方法中可以看到每次需要使用m*n的數(shù)據(jù),實際上在迭代計算的時候只使用了上一行和當前行的前一個元素
  • 也就是使用了f(m,n-1)f(m-1,n),所以我們沒有必要使用所有的矩陣,只是用兩行數(shù)組就可以
    int uniquePaths(int m, int n) {
        return dypopt(m, n);
    }
    int dypopt(int m, int n) {
        vector<int> pre(n, 1), cur(n, 1);

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                cur[j] = cur[j - 1] + pre[j];
            }
            swap(pre, cur);
        }
        return pre[n - 1];
    }
  • 時間復雜度:O(m*n)
  • 空間復雜度:O(n)

其他

  • 空間進一步優(yōu)化leetcode討論區(qū)
  • cur未更新的的值就是pre的值cur[j] = cur[j] + cur[j-1]
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容