代码随想录算法训练营第34天|62.不同路径、63. 不同路径 II、343. 整数拆分、96.不同的二叉搜索树

1.62.不同路径

题目链接:62.不同路径
文档讲解: 代码随想录

动规五部曲:
(1)确定dp数组和下标的含义
dp[ i ][ j ] 表示到达 i x j 网络的右下角有的路径数
(2)确定递推公式
机器人只能向下或者向右移动一步,那么就有dp[ i ][ j ] = dp[ i - 1 ][ j ] + dp[ i ][ j - 1]
(3)初始化
如果,m = 1 或者 n = 1,那么只有一种方法。当m,n 都大于等于2时,dp[ 0 ][ 1 ] = 1,dp[ 1 ][ 0 ] = 1
(4)遍历顺序:两层迭代,都从前往后
(5)打印数组

以上是我自己的思路,也不知道能不能做出来!初始化出现了问题,应该修改为除了dp [0][0](因为没有实际意义),dp[0] 和 dp[][0] 值都为1。遍历顺序再具体一点,先固定 i ,从前往后填满,然后令 i + 1,重复填满。运行出错,发现当起点和终点重合的时候(即 m = 1,n = 1),dp[0][0] = 1,那么就可以直接在新建列表的时候初始值为1。

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        #创建dp数组
        dp = [[1] * n for _ in range(m)]
        #初始化
        #第一行
        # for j in range(1, n):
        #     dp[0][j] = 1
        # #第一列
        # for i in range(1, m):
        #     dp[i][0] = 1
        #填满
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i][j - 1] + dp[i - 1][j]
        
        return dp[m - 1][n - 1]

2.63. 不同路径 II

题目链接:63. 不同路径 II
文档讲解: 代码随想录

动规五部曲:
(1)确定dp数组和下标
dp[ i ][ j ] 表示到达 i x j 网络的右下角有的路径数
(2)确定递归公式
dp[ i ][ j ] = dp[ i - 1 ][ j ] + dp[ i ][ j - 1],但要考虑若该点有障碍物,那么就保持初始状态
(3)初始化
新建的时候初始值为0,遍历第一行和第一列的时候,一旦某点是障碍,那么该点及之后的点都不可达,也就是保持初始化状态不变
(4)遍历顺序:两层迭代,先固定 i ,从前往后填满,然后令 i + 1,重复填满
(5)打印数组

class Solution(object):
    def uniquePathsWithObstacles(self, obstacleGrid):
        """
        :type obstacleGrid: List[List[int]]
        :rtype: int
        """
        m = len(obstacleGrid)
        n = len(obstacleGrid[0])
        #新建dp数组
        dp = [[0] * n for _ in range(m)]
        #初始化
        for j in range(n):
            if obstacleGrid[0][j] == 0:
                dp[0][j] = 1
            else:
                break
        for i in range(m):
            if obstacleGrid[i][0] == 0:
                dp[i][0] = 1
            else:
                break
        #遍历
        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]
        return dp[m - 1][n - 1]

3.343. 整数拆分

题目链接:343. 整数拆分
文档讲解: 代码随想录

动规五部曲:
(1)确定dp数组和下标含义
dp[ i ]表示拆分数字 i,可以得到的最大乘积
(2)确定递推公式
从 1 遍历到 j,两种渠道得到dp[ i ],一个是 j 与 (i - j)相乘,另一种是 j 和 dp[i - j] 相乘。因为是从1遍历到 j,所以对 j 的拆分已经在遍历过程中实现了。因此递推公式为:dp[ i ] = max(dp[ i ], j * (i - j), j * dp[i - j])。为什么还要比较dp[i]呢?因为在递推公式推导的过程中,每次计算dp[i],取最大的而已。
(3)初始化
dp[0] dp[1] 就不应该初始化,也就是没有意义的数值。因为拆分0和1是无解的,因此初始化从2开始,dp[2] = 1。
(4)遍历顺序:从前往后遍历,需要两层循环,一层为 i,一层为 j。j的结束条件是 j < i - 1 ,其实 j < i 也是可以的,不过可以节省一步,例如让 j = i - 1,的话,其实在 j = 1的时候,这一步就已经拆出来了,重复计算,所以 j < i - 1。至于 i 是从3开始,这样dp[i - j]就是dp[2]正好可以通过我们初始化的数值求出来。可以进一步优化,拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的。因此, j 遍历,只需要遍历到 n/2 就可以,后面就没有必要遍历了,一定不是最大值。
(5)打印数组

class Solution(object):
    def integerBreak(self, n):
        """
        :type n: int
        :rtype: int
        """
        dp = [0] * (n + 1)
        #初始化
        dp[2] = 1
        for i in range(3, n + 1):
            for j in range(1, i // 2 + 1):
                dp[i] = max(dp[i], j * (i - j), j * dp[i - j])
        return dp[n]

4.96.不同的二叉搜索树

题目链接:96.不同的二叉搜索树
文档讲解: 代码随想录

又是完全没有思路。

作题的步骤:画个图举例看看。
在这里插入图片描述
然后就可以发现头节点为1时,右子树会有2个节点,和头节点为3时,左子树有2个节点,这两种情况,两棵树的布局是一样的。

动规五部曲:
(1)确定数组和下标
dp[ i ]表示节点数为 i 时, 互不相同的 二叉搜索树的种类
(2)递推关系式和遍历顺序
以3为例,可以分为头节点为1、2、3的三种情况。两层循环,一个是 i,一个是 j。当以 i 为节点总数时,以 j 为头节点,左子树有 j - 1个节点,右子树有 i - j 个节点。累加公式为:dp[ i ] += dp[ j ] * dp[i - j].
(3)初始化
dp[0] = 1
(4)打印数组

class Solution(object):
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        dp = [0] * (n + 1)
        dp[0] = 1
        for i in range(1, n + 1):
            for j in range(0, i + 1):
                dp[i] += dp[j - 1] * dp[i - j]
        return dp[n]
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值