九章演算法 | Bloomberg面試題:不同的路徑
阿新 • • 發佈:2021-01-08
描述
有一個機器人的位於一個 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步向下,其餘步數自然是向右,有多少種組合?
- 利用我們中學的知識可知,答案是
根據組合公式,有
計算三數的階乘,我們就能得出答案。我們還可以進行一定的優化,展開成上述公式的最右項。設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)右移。狀態轉移方程為:
複雜度分析
- 時間複雜度: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]
更多題解參考:九章演算法-官方題解