代码随想录算法训练营第40天|整数拆分、不同的二叉搜索树

整数拆分

343. 整数拆分

给定一个正整数 n ,将其拆分为 k正整数 的和( k >= 2 ),并使这些整数的乘积最大化。

返回 你可以获得的最大乘积

示例 1:

输入: n = 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。

示例 2:

输入: n = 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

提示:

  • 2 <= n <= 58

code:

把数尽量拆成平均的

/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function(n) {
    let maxNum = -1;
    for(let k = 2; k <= n ; k++){
        let m = n % k;//余数
        maxNum = Math.max(((((n-m)/k) + 1))**(m) * (((n-m)/k)) ** (k - m), maxNum);
    }
    return maxNum;
};

dp思想:对于递推公式还是有点疑惑

/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function(n) {
    // 10 
    //  1 9
    // 2 8 
    // 3 7
    //4 6
    // 5 5
    // 6 4
    // 7 3
    // 8 2
    // 9 1
    let dp = new Array(n+1).fill(0);//要先提前初始化为0
    dp[0] = 0;
    dp[1] = 0;
    dp[2] = 1;
    // 3  
    for(let i = 3; i <= n; i++){
        for(let j = 1; j <= i/2; j++){
            dp[i] = Math.max(j*(i-j), j*dp[i-j],dp[i]);
        }
    }
    return dp[n];

};

96. 不同的二叉搜索树

96. 不同的二叉搜索树

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入:n = 3
输出:5

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 19

Code:

如果清楚二叉搜索树的特性和知道用动态规划来做这道题,这道题其实还不算特别难,但是需要画图分析一下,其实就是找规律的过程。

由于二叉搜索树的特性(比跟节点小的数一定放在左子树中,比根节点大的数一定放在右子树中),所以就需要考虑当j作为根节点的时候,会有几种情况,在对j0遍历到n;这里为什么从0开始遍历,后面会解释。

在实际分析前,需要注意的一点的,如果一棵树只有3个节点,那无论这三个节点里面的数是(1,2,3),还是(2,3,4),或者是(11,12,13)等等,只要是连续的数字,那么他们的二叉搜索树的种类个数就一定是相等的。即树有几种可能性是考虑树中有几个节点,而不是考虑树中节点的实际值。

具体来说,考虑n=4的情况,在n=4时,分为4种情况讨论:

  • 当root=1,那么可以得知对于2,3,4节点来说,这三个节点都将放在以1为根节点的树的右子树下,因为 2,3,4都大于1,那么对于右子树而言,只需要计算(2,3,4)节点的可能种类即d[3];在考虑左子树,由于没有比1还小的树节点,所以此时的左子树是为空的,即d[0]。一般来说,如果考虑d[0]的实际意义,可能会给d[0]赋值为0;

    但是需要考虑到,一棵树的种类,如果确定了根节点,那么这颗树的可能种类就是左子树的可能种类个数乘上右子树的可能种类个数,即d[3]*d[0],如果我们给d[0]赋值为0,那么d[3]*d[0]==0,这很明显和实际情况不符。再加上题目中1<=n<=19,所以我们不妨将d[0]赋值为1

  • 那么当roo=2,我们同理分析,只有(1)节点(1个节点)在右子树中,而(2,3)节点(2个节点)在左子树中,那么可能性就是d[1]*d[2]

  • 同理,当root=3,有(1,2)2个节点在右子树,只有(4)1个节点在左子树中,所以可能性是d[2]*d[1]

  • 当root=4,有(1,2,3)3个节点在右子树,0个节点在左子树,即d[3]*d[0]

    总结分析得 root==1 d[3]*d[0]

    总结分析得 root==2 d[2]*d[1]

    总结分析得 root==3 d[1]*d[2]

    总结分析得 root==4 d[0]*d[3]

    ​ 即 root==j d[i-j-1]*d[j]j0i-1(0和i-1都去得到)

    从实际意义上来理解其实也很好,如果是一颗有i个节点的树,其中一个节点已经确定了是根节点了,所以只有剩下的i-1个节点分别分配在左右子树中,所以左右子树的节点个数相加是i-1,所以上面的d[i-j-1]*d[j]中的i-j-1加上j是一定等于i-1的。

现在只需要对上面的4种情况(i==4种情况)进行求和就可以得出dp[4]dp[i]

这种规律从i=3就开始了,所以可以从i=3开始遍历,一直到题目所求的i==n

/**
 * @param {number} n
 * @return {number}
 */
var numTrees = function(n) {
    //d[i]表示有i个节点的二叉搜索树的种数
    let dp = new Array(n+1).fill(1);
    dp[2] = 2;
    for(let i = 3; i <= n; i++){
        let cn = 0;
        for(let j = 0; j < i; j++){
            cn += (dp[j] * dp[i-j-1]);
        }
        dp[i] = cn;
    }
    return dp[n];
};
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值