Day 41 动态规划 2

343. 整数拆分

代码随想录

1. 思路

(1)贪心算法

这道题最开始想到的是贪心。因为我们知道把一个数拆分成两部分,两部分越接近,乘积越大。而这两部分还可以再拆分,让四个数的乘积最大。这样拆分,最后能拆到2和3。这是因为2和3的拆分乘积比它们小。而可以发现,拆的3越多越好,但不能剩下1。因此,策略为,尽可能拆3,如果剩下1就少一个3留一个4,如果剩下2就保留这个2。这种策略可以让全局最优。

这里可以将代码优化。我对n%3进行分类讨论,这样做其实麻烦了。因为其实最后一个乘的东西就是<4的余数。可以直接用3将n减下去,在n<=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;
    }
};

(2)动态规划

【1】确定dp数组

dp数组为拆分乘积最大值,每个元素dp[i]为i可以拆分乘积的最大值。

【2】确定推导逻辑

可以将i拆成两个数,其中一个利用遍历,另一个利用之前dp的结果。这是一种非常常见的dp逻辑,可以将无限循环转换成有限循环。假设拆成j和i-j,则

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

之所以要保留dp[i]以及i*(i-j),是因为dp中的元素都是i经过拆分乘积得到的,不一定大于不拆分的结果i。

【3】确定dp顺序

从前到后

【4】确定初始值

dp中的元素是拆分得到的乘积,因此对应的i必须可拆分。因此,i=0,1没有意义,i=2时给定1。

【5】进行尝试

可以将代码进行优化,因为每次拆分j的时候,j不能太大,可以将限制设定在i/2。

class Solution {
public:
    int integerBreak(int n) {
        if(n<=3) return 1*(n-1);
        vector<int> dp(n + 1, 0);
        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];
    }
};

96. 不同的二叉搜索树

代码随想录

 1. 思路

这道题属于二叉树,因此两个分支可以继续递归,属于动态规划的范畴

(1)确定dp数组

dp数组是可以构建的二叉树个数,dp[i]是给定1-i节点可以构造的二叉树个数。

(2)确定递推逻辑

可以通过遍历将i之前的元素分成两堆,之后进行组合。公式为:

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

(3)确定初始化

在i=1时,相当于只有一个节点的二叉树,因此有1个,dp[0] = 1。

(4)遍历顺序 (5)举例

从前到后

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n+1);
        dp[0] = 1;
        dp[1] = 0;
        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];
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值