更弱智的算法学习 day34

62.不同路径

  • 确定dp数组(dp table)以及下标的含义

dp(m,n)是到达(m,n)时,有多少种可能的路径

  • 确定递推公式

dp(m,n) = dp(m-1,n) + dp(m,n-1)

  • dp数组如何初始化

dp(1,0)= 1,dp(0,1) = 1

  • 确定遍历顺序

由dp(m,n) = dp(m-1,n) + dp(m,n-1),应该从起点向终点遍历

  • 举例推导dp数组

需要注意:从起点开始(0,0),无论到达(k,0)或(0,k)都只有一条路径,不要混淆了

python 复制代码
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        @cache

        def dp(m,n):
            if n==0 or m==0:
                return 1
            return dp(m-1,n) + dp(m,n-1)
        return dp(m-1,n-1)

63. 不同路径 II

  • 确定dp数组(dp table)以及下标的含义定义

dp[i][j]表示从起点 (0,0)到达位置 (i,j)的不同路径数。

  • 确定递推公式

如果该位置是障碍物:dp[i][j] = 0

如果不是障碍物:dp[i][j] = dp[i-1][j] + dp[i][j-1]

  • dp数组如何初始化

dp(1,0)= 1,dp(0,1) = 1,遇到障碍时,路径数量应该为0

  • 确定遍历顺序

由dp(m,n) = dp(m-1,n) + dp(m,n-1),应该从起点向终点遍历

  • 举例推导dp数组

在相对特殊的情况没想清楚,例如边缘上有障碍物,且仅有该道路时,应该也设为0。如[[0,1,0,0]]

同时,由于输入时m-1和n-1,存在越界可能,需要处理;

python 复制代码
class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:


        @cache
        def dp(m,n): 
            if m<0 or n<0:
                return 0
            if obstacleGrid[m][n] == 1:
                return 0
            if n==0 and m==0:
                return 1
            return dp(m-1, n) + dp(m, n-1)

        m = len(obstacleGrid)
        n = len(obstacleGrid[0])


        return dp(m-1,n-1)

        

相对标准的方法

python 复制代码
class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:

        m, n = len(obstacleGrid), len(obstacleGrid[0])

        if obstacleGrid[0][0] == 1 or obstacleGrid[m-1][n-1] == 1:
            return 0
            
        dp = [[0] * n for _ in range(m)]
        dp[0][0] = 1  # 起点
        
        # 初始化第一列
        for i in range(1, m):
            if obstacleGrid[i][0] == 0:  # 没有障碍物
                dp[i][0] = dp[i-1][0]  # 只能从上方来
        
        # 初始化第一行
        for j in range(1, n):
            if obstacleGrid[0][j] == 0:  # 没有障碍物
                dp[0][j] = dp[0][j-1]  # 只能从左方来
        
        # 填充内部格子
        for i in range(1, m):
            for j in range(1, n):
                if obstacleGrid[i][j] == 0:  # 没有障碍物
                    dp[i][j] = dp[i-1][j] + dp[i][j-1]
                # 有障碍物时保持0(默认值)
        
        return dp[m-1][n-1]
        

整数拆分 (可跳过)

没有想得特别的清楚,仔细考虑一下:

  • 确定dp数组(dp table)以及下标的含义定义

这里的dp数组也即给定的整数n目前为止还剩下多少

  • 确定递推公式

dp[i] = max(j * dp[i-j] , j*(i-j), dp[i])

也即dp[i]是 i拆成的j和i-j的乘积或i拆成的i和dp(i-j)的乘积,或i本身

  • dp数组如何初始化

因为n>=2,初始化dp(2)==1即可

  • 确定遍历顺序

由dp[i] = max(j * dp[i-j] , j*(i-j), dp[i]),应该从起点向终点遍历

  • 举例推导dp数组
python 复制代码
class Solution:
    def integerBreak(self, n: int) -> int:
        dp = [0] * (n+1)
        dp[2] =  1      
        for i in range(3,n+1):
            for j in range(1,i-1):
                dp[i] = max(j * dp[i-j] , j*(i-j), dp[i])
        return dp[n]

不同的二叉搜索树 (可跳过)

  • 确定dp数组(dp table)以及下标的含义定义

dp(n)也即有n个节点的二叉搜索树有多少种

  • 确定递推公式

来看看n为3的时候,有哪几种情况。

当1为头结点的时候,其右子树有两个节点,看这两个节点的布局,是不是和 n 为2的时候两棵树的布局是一样的啊!

当3为头结点的时候,其左子树有两个节点,看这两个节点的布局,是不是和n为2的时候两棵树的布局也是一样的啊!

当2为头结点的时候,其左右子树都只有一个节点,布局是不是和n为1的时候只有一棵树的布局也是一样的啊!

发现到这里,其实我们就找到了重叠子问题了,其实也就是发现可以通过dp[1] 和 dp[2] 来推导出来dp[3]的某种方式。

思考到这里,这道题目就有眉目了。

dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量

元素1为头结点搜索树的数量 = 右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量

元素2为头结点搜索树的数量 = 右子树有1个元素的搜索树数量 * 左子树有1个元素的搜索树数量

元素3为头结点搜索树的数量 = 右子树有0个元素的搜索树数量 * 左子树有2个元素的搜索树数量

有2个元素的搜索树数量就是dp[2]。

有1个元素的搜索树数量就是dp[1]。

有0个元素的搜索树数量就是dp[0]。

所以dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2]

如图所示:

dp[i] += dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量]

j相当于是头结点的元素,从1遍历到i为止。

所以递推公式:dp[i] += dp[j - 1] * dp[i - j]; ,j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量

  • dp数组如何初始化

初始化为0即可,其中dp[0] = 1

  • 确定遍历顺序

顺序遍历即可

  • 举例推导dp数组
python 复制代码
class Solution:
    def numTrees(self, n: int) -> int:
        dp = [0] * (n+1)

        dp[0] = 1

        for i in range(1,n+1):
            for j in range(1,i+1):
                dp[i] += dp[j-1] * dp[i-j]
        
        return dp[n]
相关推荐
AllFiles2 小时前
用Python turtle画出标准五星红旗,原来国旗绘制有这么多数学奥秘!
python
亲爱的非洲野猪2 小时前
Java线程池深度解析:从原理到最佳实践
java·网络·python
写点什么呢2 小时前
AD21安装激活
学习
用户1377940499932 小时前
基于遗传算法实现自动泊车+pygame可视化
python
4***17542 小时前
强化学习中的蒙特卡洛方法
python
pen-ai2 小时前
打通 Python 与 C++ 的参数传递机制
开发语言·c++·python
至此流年莫相忘2 小时前
Python之深拷贝和浅拷贝
python
像风一样自由20203 小时前
XGBoost、LightGBM、CatBoost 原理深度剖析与全面对比
python
用户230826676653 小时前
Python的管道符(|)联合类型语法糖
python