1. 程式人生 > 其它 >九章演算法 | Bloomberg面試題:不同的路徑

九章演算法 | Bloomberg面試題:不同的路徑

技術標籤:演算法動態規劃資料結構javac++

描述

有一個機器人的位於一個 m × n 個網格左上角。

機器人每一時刻只能向下或者向右移動一步。機器人試圖達到網格的右下角。

問有多少條不同的路徑?

注意:n和m均不超過100,且答案保證在32位整數可表示範圍內。

線上評測地址:

LintCode 領釦

樣例1:

Input: n = 1, m = 3
Output: 1        
Explanation: Only one path to target position.

樣例2:

Input:  n = 3, m = 3
Output: 6        
Explanation:
        D : Down
        R : Right
        1) DDRR
        2) DRDR
        3) DRRD
        4) RRDD
        5) RDRD
        6) RDDR

挑戰

要求時間複雜度為 O(n)

解題思路

  • 不難發現,機器人從左上角走到右下角,需要向下走m - 1步,向右走n - 1步,那麼總步數也是一定的,為m + n - 2步。問題就轉化成,從m + n - 2步中選出m - 1步向下,其餘步數自然是向右,有多少種組合?
  • 利用我們中學的知識可知,答案是

v2-65108caeeb37e87b1ba028518a425cba_b.jpg

根據組合公式,有

v2-c731670d039be54132f5314d53161448_b.jpg

計算三數的階乘,我們就能得出答案。我們還可以進行一定的優化,展開成上述公式的最右項。設m < n,那麼時間複雜度就只有O(m)。

複雜度分析

  • 時間複雜度: O(min(m,n))。計算階乘的時間複雜度與m, n中的較小數成線性關係。
  • 空間複雜度:O(1)。常量空間。
class Solution:

    """
    @param m: positive integer (1 <= m <= 100)
    @param n: positive integer (1 <= n <= 100)
    @return: An integer
    """

    def uniquePaths(self, m, n):
        # corner case
        if (m == 1 or n == 1):
            return 1

        #
保證m <= n if (m > n): m, n = n, m # 計算階乘 temp = 1 res = 1 for i in range(1, m): temp *= i for i in range(n, m + n - 1): res *= i return res//temp

動態規劃

解題思路

  • 建立二維陣列dp,令dp[i][j]表示到達 i, j的最多路徑數。
  • 初始化:對於第一行 dp[0][j],或者第一列 dp[i][0],都只有一條路徑。
  • 機器人到達位置(i, j)有兩種方式:從(i - 1, j)下移和從(i, j - 1)右移。狀態轉移方程為:

v2-66a923064ae13e99094376362324d5e4_b.jpg

複雜度分析

  • 時間複雜度:O(mn)。遍歷dp陣列進行動態規劃。
  • 空間複雜度:O(mn)。建立的dp陣列的大小。

程式碼

class Solution:

    """
    @param m: positive integer (1 <= m <= 100)
    @param n: positive integer (1 <= n <= 100)
    @return: An integer
    """

    def uniquePaths(self, m, n):
        dp = [[0] * n for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if i == 0 or j == 0:
                    dp[i][j] = 1
                else:
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
    return dp[m - 1][n - 1]

優化後的動態規劃

dp可以優化為一維滾動陣列。當第i次遍歷到dp[j]時,dp[j]表示到達(i, j)最多的路徑數。遞推公式為:dp[j]+=dp[j−1]。

複雜度分析

  • 時間複雜度:O(mn)。遍歷dp陣列進行動態規劃。
  • 空間複雜度:O(n)。建立的一維dp陣列的大小。

程式碼

class Solution:
    """
    @param m: positive integer (1 <= m <= 100)
    @param n: positive integer (1 <= n <= 100)
    @return: An integer
    """
    def uniquePaths(self, m, n):
        dp = [0] * n
        dp[0] = 1
        for i in range(m):
            for j in range(1, n):
                dp[j] += dp[j - 1]
    return dp[n - 1]

更多題解參考:九章演算法-官方題解