Day 41 | 343. 整数拆分 & 96. 不同的二叉搜索树

343. 整数拆分

dp解题思路: 

        本题不用纠结具体拆成几个,只用将i拆分成j+(i-j),j从1开始向后遍历,i-j并不是单纯的i-j,而是i-j能拆分出的最大乘积。会有以下两种情况:

将 i 拆分成 j 和 i-j 的和,且 i-j 不再拆分成多个正整数,此时的乘积是 j ×(i−j)

将 i 拆分成 j 和 i-j的和,且 i-j 继续拆分成多个正整数,此时的乘积是 j ×dp[i−j]

dp[0],dp[1]没有具体意义,dp[2]初始化为1,i从3开始遍历得到dp[n]。

①确定dp数组以及下标含义

        dp[i]:整数i的拆分后的最大乘积。

②确定递推公式

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

       //取拆分和不拆分后的乘积最大值

       //注意还要和dp[i]自身进行比较,因为不能保证本次循环得到的dp[i]一定小于下次的dp[i]

③dp数组如何初始化

        dp[2]=1

        dp[0]/dp[1]初始化没有实际意义也用不到,i从3开始遍历。

④确定遍历顺序

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

dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历,先有dp[i - j]再有dp[i]。

枚举j的时候,是从1开始的。i是从3开始,这样dp[i - j]就是dp[2]正好可以通过我们初始化的数值求出来。

⑤举例推导dp数组

    public int integerBreak(int n) {
        int[] dp=new int[n+1];
        dp[2]=1;
        for(int i=3;i<=n;i++){
            for(int j=1;j<i;j++){
                dp[i]=Math.max(dp[i],Math.max(dp[i-j]*j,(i-j)*j));
            }
        }
        return dp[n];
    }

96. 不同的二叉搜索树

 

dp解题思路:

        由n=2和n=3可以看出,当n=3时,1为根节点的右子树形态和n=2时相同。2为根节点的左右子树与n=1时(左边一颗右边一颗)形态相同,3为根节点的左子树形态和n=2时相同,由此推断n=3可由n=1/2推断出来。

        n=3,为1为根节点+2为根节点+3为根节点 树的数量之

1为根节点,树的数量为左子树0个节点,右子树2,3两个节点的树的乘积 =dp[0]*dp[2]

2为根节点,树的数量为左子树1个节点,右子树1个节点的树的乘积。 =dp[1]*dp[1]

3为根节点,树的数量为左子树1,2两个节点,右子树0个节点的树的乘积。 =dp[2]*dp[0]

-->  dp[n]=dp[0]*dp[n-1]+dp[1]*dp[n-2]+…+dp[n-1]*dp[0];

①确定dp数组以及下标含义

        dp[i]:有i个节点的二叉搜索树个数。

②确定递推公式

      dp[i]+=dp[j-1]*dp[i-j]

      //其中j为根节点,j-1为左子树有j-1个节点,i-j为右子树有i-j个节点

      //共有i个节点,j从1开始遍历到i,代表根节点从1一直到i,每次dp[i]加上第二层循环中不同j值作为根节点的树的个数。

③dp数组如何初始化

        dp[0]=1;

④确定遍历顺序

        dp[i]+=dp[j-1]*dp[i-j]

        i的状态总是依赖i之前节点数i-j的状态,从1向后遍历。

⑤举例推导dp数组

    public static int numTrees(int n) {
        int[] dp=new int[n+1];
        dp[0]=1;
        //共i个节点,j为根节点,(j-1)个左子树,(i-j)个右子树。
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++){
                //i个节点的树共有 左子树的搜索树个数*右子树的搜索树个数
                dp[i]+=dp[j-1]*dp[i-j];
            }
        }
        return dp[n];
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值