LeetCode刷題——62. 不同路徑

題目

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

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

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

在這裏插入圖片描述
例如,上圖是一個7 x 3 的網格。有多少可能的路徑?

示例 1:

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

示例 2:

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

提示:

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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/unique-paths

思路

這個題目和爬樓梯問題很像。

很容易想出遞歸解法。機器人每次只能向下或者向右移動一步,網格右下角記爲終點,到達終點有兩種方法: 從終點位置上面往下走一步到達;從左邊往右走一步到達。

在這裏插入圖片描述

所以只要用反向的思維就可以寫出遞歸代碼了。注意這是一個n行m列的網格。

代碼

遞歸

class Solution(object):
    def unique(self, m, n):
        # 如果到達了起點,就是一種解法
        if m == 0 and n == 0:
            return 1

        ways = 0

        # 如果可以向左回退一步
        if m >= 1:
            ways = self.unique(m - 1, n)
        # 如果可以向上回退一步
        if n >= 1:
            ways += self.unique(m, n - 1)

        return ways


    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        # 終點是m-1,n-1
        return self.unique(m-1,n-1)

在這裏插入圖片描述

雖然思路是對的,但是遞歸的方式是比較低效的,這裏導致了計算超時。參閱LeetCode刷題之動態規劃思想,我們可以將其改成記憶化搜索的方式,解決重疊子問題。

記憶化搜索

dp = {(0,0) : 1} #起點

class Solution(object):
    def unique(self, m, n):
        if (m,n) not in dp:
            ways = 0

            # 如果可以向左回退一步
            if m >= 1:
                ways = self.unique(m - 1, n)
            # 如果可以向上回退一步
            if n >= 1:
                ways += self.unique(m, n - 1)

            dp[(m,n)] = ways
        return dp[(m,n)]


    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        # 終點是m-1,n-1
        return self.unique(m-1,n-1)

在這裏插入圖片描述

動態規劃

動態規劃的解法也很簡單,從起點開始考慮。dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 這句代碼表示要達到第[i][j]個格子,可以有它的左邊那麼格子或上面那個格子達到。

我們只要處理好邊界值,整個代碼就很清爽。這點先處理邊界值的思想也體現在了64. 最小路徑和問題裏面。

class Solution(object):
    def uniquePaths(self, m, n):
        # n行 m 列的列表          外層不能使用*,否則會淺拷貝內層
        dp = [[0] * m for _ in range(n)]

        # 先設定好邊界值
        for i in range(0, n):
            dp[i][0] = 1

        for j in range(1, m):
            dp[0][j] = 1

        for i in range(1, n):
            for j in range(1, m):
                # dp[i][j] = 左邊一步加上面一步的結果
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

        return dp[-1][-1]

在這裏插入圖片描述
刷到了8ms。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章