《录鼎记》——动态规划part03

今日任务:

343. 整数拆分

  • 96.不同的二叉搜索树

一、整数拆分

力扣题目链接 (opens new window)

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

(困)

还是按东归五部曲走吧:1、dp数组及下标的含义

本题中dp[i]是指对于数字i拆分的最大乘积。

2、确定递推公式

得到dp[i]有两种方式,分别对应只拆分一次和拆分多次,

只拆分一次:j*(i-j)

拆分多次:j*dp[i-j],这个代表拆分多次是因为联系到了前面的值,而前面是拆分过的了。

3、dp初始化

dp[0],dp[1]的值是无效值,因为他们无法进行拆分为正整数和,所以可以直接对dp[2]进行初始化,dp[2]=1。

4、遍历顺序,由于后面的最大值可能取决于前面的最大值,所以应该从前向后遍历。

这里的遍历可以优化,毕竟j过了i/2之后就和前面的重合了。

可以这么写:

for (int i = 3; i <= n ; i++) {
    for (int j = 1; j <= i / 2; j++) {
        dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
    }
}

5、举例推导dp数组

看着还挺简单(狗头)

class Solution {
public:
    int integerBreak(int n) {
        vector<int> dp(n+1);
        dp[2] =1;
        for(int i =3;i<=n;i++){
            for(int j=1;j<=i/2;j++){
                dp[i] =max(dp[i],max(j*(i-j),dp[i-j]*j));
            }
        }
        return dp[n];

    }
};

但这题这里不能只维护两个元素了,因为前面的任何值可能被用到,无法确定该维护多少。

贪心方法:

当分解式中拆分成4以上时,比如5,那么再次拆分为 2 * 3 = 6,结果显然大于5;所以,根据数学推理,很容易得出,分解式中3越多越好,这样乘积才会越来越大;当只分解式中含有4的时候,拆分成2 * 2,则更好。故:分解式应该尽可能的拆分成更多的3。当只剩下4的时候,就直接取4就是最大值。

class Solution {
public:
    int integerBreak(int n) {
        if(n==2) return 1;
        if(n==3) return 2;
        if(n==4) return 4;
        int result =1;
        while(n>4){
            result*=3;
            n-=3;
        }
        result *=n;
        return result;

    }
};

二、不同的二叉搜索树

力扣题目链接 (opens new window)

给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?

并不是很理解,要按动归五部曲来走一遍

1、确定dp数组以及下标含义

dp[i]是i个节点能组成的组成二叉搜索树的个数。

关于二叉搜索树,可以看这里:

(43条消息) 【数据结构】——二叉搜索树_努力学习的少年的博客-CSDN博客

2、确定递推公式

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

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

所以递推公式:dp[i] += dp[j - 1] * dp[i - j]; 

3、dp数组如何初始化

dp[0]=1

由于要做乘法的乘数之一。

4、遍历顺序

其值依赖于前面节点数的状态所以从前向后遍历

5、第五步:举例推导

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n+1);
        dp[0] =1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++){
                dp[i] +=dp[j-1]*dp[i-j];
            }
        }
        return dp[n];

    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值