问题
有一个m x n的格子,从左上角走到右下角,每次只能向右或向下,问有多少种走法
思路
dp解法
当你处在某个格子coordinate(i,j),只可能从上方来,或者从左方来,那么把你“左上角到你左方格子”有多少种走法,加上“左上角到你上方格子”有多少种走法,就是“到这个coordinate(i,j)格子”有多少种走法。
[dp[i][j] = dp[i-1][j] + dp[i][j+1]
]
dp矩阵初始化为1,因为对于最上面一行和最左边一列,只有一种走法。
dp矩阵可以优化成数组,这里不多解释了,和之前 486. Predict the Winner 给出的三个gif图是一样的道理。
时间复杂度O(n*m)
空间复杂度O(n)或O(m),可以自己取小的那个O
排列组合的解法
考虑一个3行7列的格子,一定会走(3-1)+(7-1)也就是8步,减一是因为起点和终点不需要走。
那么在这8步里面,我们只考虑哪一步向下走,是有(3-1)种选择,也就是两种选择,这样组合出来的就是(C^2_8)。
或者在这8步里面,我们只考虑哪一步向右走,有(7-1)种选择,组合出来就是(C^6_8),跟(C^2_8)是等价的。
因为8步里面要么向右走,要么向下走。我们只需要纯粹考虑两种。比如只考虑向下走有哪两步,剩下六步都是向右走。比如只考虑向右走有哪6步,剩下两步都会向下走。
所以我们计算(C^{min(n-1, m-1)}_{n+m-2})即可。这里给一下排列组合的公式,(C^m_n = frac{n!}{m! (n-m)!}, A^m_n = frac{n!}{(n-m)!})。
时间复杂度O(min(n, m)),空间复杂度O(1)
代码
dp解法
class Solution(object):
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
dp = [1 for _ in range(n)]
for i in range(1,m):
for j in range(1,n):
dp[j] = dp[j] + dp[j-1]
return dp[n-1]
排列组合的解法
class Solution(object):
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
n, m = n+m-2, min(n-1, m-1)
numerator = denominator = 1
for i in range(m):
numerator *= n-i
denominator *= i+1
return numerator / denominator