Leetcode62. Unique Paths-动态规划/数学公式

题目

题目链接

思路

两种思路:1.动态规划 2.数学公式

  1. 动态规划1
    用一个表 d p dp dp记录每个位置的总数,每个位置上只能从左或从上到达,因此值是上边格子的值加上左边格子的值:
    d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j] = dp[i - 1][j] + dp[i][j - 1] dp[i][j]=dp[i1][j]+dp[i][j1]
11111
12345
1361015
14102035
  1. 动态规划2
    优化空间复杂度
    由于第一行和第一列一定都是1,每次只是更新红框内的行,因此只记录这一行即可
    在这里插入图片描述
  2. 数学公式
    由于从左上角到右下角,一定有m - 1次向下,n - 1次向右,
    走过路径长度一定为(m - 1) + (n - 1),
    因此总路径数就是在这(m - 1) + (n - 1)中选出m - 1个向下,或n - 1个向右的组合数,
    C m + n − 2 m − 1 C_{m+n-2}^{m-1} Cm+n2m1,或 C m + n − 2 n − 1 C_{m+n-2}^{n-1} Cm+n2n1
    对组合数 C a + b a = ( a + b ) ! a ! b ! C_{a+b}^{a}=\frac{(a+b)!}{a!b!} Ca+ba=a!b!(a+b)!,
    如果直接求三个阶乘数,可能时间更长,考虑到分子和分母都从1开始累乘,可以进行化简:
    C a + b a = ( a + b ) ! a ! b ! = ( ∏ i = m a x ( a , b ) a + b i ∗ ∏ i = 1 m a x ( a , b ) i ) / ( ∏ i = 1 m i n ( a , b ) i ∗ ∏ i = 1 m a x ( a , b ) i ) = ∏ i = m a x ( a , b ) a + b i / ∏ i = 1 m i n ( a , b ) i C_{a+b}^{a}=\frac{(a+b)!}{a!b!}=(\prod \limits_{i=max(a,b)}^{a+b} i* \prod \limits_{i=1}^{max(a,b)}i)/(\prod \limits_{i=1}^{min(a,b)}i * \prod \limits_{i=1}^{max(a,b)}i)=\prod \limits_{i=max(a,b)}^{a+b}i/\prod \limits_{i=1}^{min(a,b)}i Ca+ba=a!b!(a+b)!=(i=max(a,b)a+bii=1max(a,b)i)/(i=1min(a,b)ii=1max(a,b)i)=i=max(a,b)a+bi/i=1min(a,b)i
    可见可以省去两次 ∏ i = 1 m a x ( a , b ) i \prod \limits_{i=1}^{max(a,b)}i i=1max(a,b)i的求积

复杂度

  • 时间复杂度
  1. 填表,表格尺寸为 m ∗ n m*n mn, O ( m ∗ n ) \mathcal{O}(m*n) O(mn)
  2. DP优化空间,也要计算每个位置的值, O ( m ∗ n ) \mathcal{O}(m*n) O(mn)
  3. 数学公式,计算乘积次数为 m + n − 2 − m a x ( m − 1 , n − 1 ) + m i n ( m − 1 , n − 1 ) m+n-2 - max(m-1, n-1) + min(m-1, n - 1) m+n2max(m1,n1)+min(m1,n1),因此为 O ( m + n ) \mathcal{O}(m+n) O(m+n)
  • 空间复杂度
  1. DP填表,表格尺寸为 m ∗ n m*n mn, O ( m ∗ n ) \mathcal{O}(m*n) O(mn)
  2. DP优化:只记录一行, O ( n ) \mathcal{O}(n) O(n)
  3. 数学公式,每次调用只有几个变量, O ( 1 ) \mathcal{O}(1) O(1)

代码

DP- O ( m ∗ n ) \mathcal{O}(m*n) O(mn)时间, O ( m ∗ n ) \mathcal{O}(m*n) O(mn)空间

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        if m == 1 or n == 1:
            return 1
        # 保留整个dp列表
        dp = [[0 for _ in range(n)] for _ in range(m)]
        for i in range(m):
            dp[i][0] = 1
        for j in range(n):
            dp[0][j] = 1
        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[-1][-1]

在这里插入图片描述

DP- O ( m ∗ n ) \mathcal{O}(m*n) O(mn)时间, O ( n ) \mathcal{O}(n) O(n)空间

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        if m == 1 or n == 1:
            return 1
        dp = [1 for _ in range(n - 1)]
        for i in range(m - 1):
            for j in range(n - 1):
                # 只更新这一行
                if j == 0:
                    dp[j] += 1
                else:
                    dp[j] += dp[j - 1]
        return dp[-1]

在这里插入图片描述

数学公式法- O ( m + n ) \mathcal{O}(m+n) O(m+n)时间, O ( 1 ) \mathcal{O}(1) O(1)空间

def mul_between(n1, n2):
    """n1到n2间的所有自然数的乘积"""
    result = 1
    for n in range(n1, n2 + 1):
        result *= n
    return result
    

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        if m == 1 or n == 1:
            return 1
        return mul_between(max(m, n), m - 1 + n - 1) // mul_between(1, min(m, n) - 1)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值