1. 程式人生 > >leetcode 62.不同路徑

leetcode 62.不同路徑

題目描述:

一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記為“Start” )。

機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為“Finish”)。

問總共有多少條不同的路徑?

思路 :

從左上角到右下角總共需要走 m+n-2 步,其中 m-1 步向下,剩下的 n-1 步向右。所以這其實是一個簡單的排列組合問題...

答案應該是 C( m+n-2 , m-1 ),和與它對稱的 C( m+n-2 , n-1 )。挑一個簡單的計算就行。時間複雜度應該是O(min(m,n))

int uniquePaths(int m, int n) {
        int N=m+n-2;
        int M=m<n?m-1:n-1;
        //計算 C(N,M)
        //根據:C(N,i)=C(N,i-1)*(N-i+1)/i;
        //由於是先乘再除的,可能會出現中間結果超出int的情況,所以用long
        long ans=1;
        for(int i=1;i<=M;i++)
            ans=ans*(N-i+1)/i;
        return ans;
    }

測試執行0ms。

看了一下同樣是0ms的其他程式碼,感覺有點複雜。先去吃午飯再回來琢磨...

//邊吃午飯邊更新:

假定a[i][j]代表從左上角到 ( i, j ) 格子的路徑總數。考慮到能抵達格子( i , j )只有兩類方式:1,從它左邊走過來;2,從它上面走過來。總路徑數,應該是這兩類路徑數之和。所以 a[i,j] = a[i-1,j] + a[i,j-1]。

int uniquePaths(int m, int n) {
        //初始化一個矩陣
        int a[m][n]{0};
        //對於第一行上的格子,只有一條路徑:一路向右
        for(int i=0;i<n;i++)
            a[0][i]=1;
        //第一列同理
        for(int i=0;i<m;i++)
            a[i][0]=1;
        //其餘格子:a[i][j]=a[i-1][j]+a[i][j-1];
        for(int i=1;i<m;i++)
            for(int j=1;j<n;j++)
                a[i][j]=a[i-1][j]+a[i][j-1];
        return a[m-1][n-1];
    }

注意我用了a[m][n],現在C++裡都可以這樣了?!

這個演算法的時間複雜度是O(m*n),空間複雜度也是O(m*n)。

另外注意到空間還有優化的餘地,改進演算法如下:

int uniquePaths(int m, int n) {
        //初始化一個矩陣
        int a[n]{0};
        //第一行
        for(int i=0;i<n;i++)
            a[i]=1;
        //迭代求第i行的值
        for(int i=1;i<m;i++)
            for(int j=1;j<n;j++)
                a[j]=a[j]+a[j-1];
        return a[n-1];
    }

時間複雜度不變,空間優化為O(n)。如果有必要,可以通過調換對行、列的迴圈順序,把空間優化為O(min(m,n))。