1.最开始用的dfs遍历的方法,应该能算出正确答案,但是超时了。思考了一下时间复杂度,这个dfs方法的复杂度应该是(m+n−1)Cm+n−2m−1(m+n-1)C_{m+n-2}^{m-1}(m+n−1)Cm+n−2m−1,超时的样例是m=23,n=12,我计算了一下复杂度的具体数值,为262662462526464000,肯定会超时,所以最好能用其他方法,就不要暴力搜索了。
(需要注意leetcode的输入是许多案例同时输入,所以在定义并调用需要修改的类变量之前,一定要对类变量进行初始化,不然类变量会保持上一次输入后的状态)
class Solution:
count = 0
dirs = [[0, 1], [1, 0]]
def dfs(self, m: int, n: int, r: int, c: int):
if r == m-1 and c == n-1:
Solution.count += 1
return
for Dir in Solution.dirs:
tmpr = r + Dir[0]
tmpc = c + Dir[1]
if tmpr >= m or tmpc >= n:
continue
self.dfs(m, n, tmpr, tmpc)
return
def uniquePaths(self, m: int, n: int) -> int:
Solution.count = 0
self.dfs(m, n, 0, 0)
return Solution.count
2.第二种方法尝试的是动态规划的方法。因为到每个格子的步数是一定的,所以可以将该步数当作阶段变量考虑,到k步格子的路径条数,仅与到k-1步格子的路径条数相关,更加精确的说,仅与到k步格子的左或上相邻格子(均为k-1步格子)的路径相关,所以可以用动态规划的思想求解。其实我原来想过用动态规划的方法,不过觉得dfs思路简单就想暴力搞一发试试,然后果然超时了。所以还是该用动态规划就用动态规划吧。
dp[i][j]dp[i][j]dp[i][j]代表到第i行第j格总共有多少路径。
状态转移方程:
dp[i][j] = dp[i-1][j]+dp[i][j-1]
完整代码:
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 直接全部初始化为1,减少了单独初始化第一行和第一列的过程
# 需要注意dp[0][0]也为1
dp = [[1 for i in range(n)] for j in range(m)]
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j]+dp[i][j-1]
return dp[m-1][n-1]
3.第三种方法是排列组合的方法
从初始点(0,0)到目标点(m-1, n-1)的路径中,总共需要经过(m+n-2)步,其中(m-1)步向下,(n-1)步向右。此时的问题就转化为了,在这(m+n-2)步中,第多少步向下,第多少步向右。用排列组合的惯用黑白球说法来说,就是(m-1)个黑球和(n-1)个白球的排列组合问题。问题转化后,求解就很简单了,用公式Cm+n−2m−1C_{m+n-2}^{m-1}Cm+n−2m−1即可求解。
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
return int(math.factorial(m+n-2)/math.factorial(m-1)/math.factorial(n-1))