代码随想录打卡—day41—【DP】— 8.26+27 DP基础3

这篇具有很好参考价值的文章主要介绍了代码随想录打卡—day41—【DP】— 8.26+27 DP基础3。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 343. 整数拆分

343. 整数拆分

一开始做 没有思路,学习了题解才,ac代码:

class Solution {
public:
    int dp[60];  // 含义:i 把它拆分成若干个数,这些数的乘积最大的值
    /*
    很妙这里j的含义 ,如果是我直觉会用k作为其中一个循环 但不知道是不是要三个循环...
    j的含义i的拆分因子: 因为k大于等于2 所以至少两个因子 所以 j = 1,...,i-1
    dp[i] = max(dp[i], max(j*(i-j) , dp[i-j]*j))
                        拆分成两个  拆分2个以上
    dp[2] = 1;
    i++


    2 3 4 5 6
    1 2 4 
    */
    int integerBreak(int n) 
    {
        dp[2] = 1;
        if(n == 2)return dp[2];

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

    }
};

后来仔细看题解,其实 for - j 的次数可以优化——


注意 枚举j的时候,是从1开始的。从0开始的话,那么让拆分一个数拆个0,求最大乘积就没有意义了。

优化1:

j 的结束条件是 j < i - 1 ,其实 j < i 也是可以的,不过可以节省一步,例如让j = i - 1,的话,其实在 j = 1的时候,这一步就已经拆出来了,重复计算,所以 j < i - 1

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

优化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));
    }
}

因为拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的。

例如 6 拆成 3 * 3, 10 拆成 3 * 3 * 4。 100的话 也是拆成m个近似数组的子数 相乘才是最大的。

只不过我们不知道m究竟是多少而已,但可以明确的是m一定大于等于2,既然m大于等于2,也就是 最差也应该是拆成两个相同的 可能是最大值。

那么 j 遍历,只需要遍历到 n/2 就可以,后面就没有必要遍历了,一定不是最大值。

至于 “拆分一个数n 使之乘积最大,那么一定是拆分成m个近似相同的子数相乘才是最大的” 这个我就不去做数学证明了,感兴趣的同学,可以自己证明。


题解的贪心做法:

本题也可以用贪心,每次拆成n个3,如果剩下是4,则保留4,然后相乘,但是这个结论需要数学证明其合理性!

2 96. 不同的二叉搜索树

96. 不同的二叉搜索树

看到题目一开始又是懵的,看了题解才知道从n=1 n=2 到n=3可以借助前n=1,n=2推出来,找到规律,AC代码:文章来源地址https://www.toymoban.com/news/detail-676272.html

class Solution {
public:
    int dp[20];  // 恰由i个节点组成的不同的二叉线索树最大的数目
    /*
    dp[0] = 0;
    dp[1] = 1;
    dp[2] = 2;
    dp[3] = dp[0]*dp[2] + dp[1]*dp[1] + dp[2]*dp[0]

    for(int j = 1; j <= i; j++)
        dp[i] += dp[j-1]*dp[n-j];
    
    i++

    0 1 2 3 4
    0 1 2 5 

    */
    int numTrees(int n) 
    {
        dp[0] = 1;  // 没有实际含义 为了凑结果的
        dp[1] = 1;
        dp[2] = 2;

        for(int i = 3; i <= n; i++)
            for(int j = 1;j <= i; j++)
                dp[i] += dp[j-1]*dp[i-j];
        
        return dp[n];
    }
};

到了这里,关于代码随想录打卡—day41—【DP】— 8.26+27 DP基础3的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • day78【代码随想录】区间DP专题

    1、多边形三角剖分的最低得分 2、猜数字大小 II 3、让字符串成为回文串的最少插入次数 4、切棍子的最小成本 5、戳气球 6、合并石头的最低成本 分析: 大佬详细题解 分析: 这一段题解是灵魂! 大佬题解 类似于算法书中的矩阵连乘问题 分析: 跟判断回文串思路一样,但是

    2023年04月13日
    浏览(29)
  • 代码随想录Day41-图论:力扣第797m、200m、695m、1020m、130m题

    题目链接 代码随想录文章讲解链接 方法一:DFS 用时:11m43s 思路 时间复杂度: O ( n ⋅ 2 n ) O(n cdot 2^n) O ( n ⋅ 2 n ) ,n是节点个数,最坏情况每个节点都可以去往任意一个在它后面的节点,那么第i个节点去到最后一个节点的路径数就有 2 n − i − 2 2^{n-i-2} 2 n − i − 2 ,就是

    2024年02月06日
    浏览(33)
  • 【代码随想录打卡】快慢指针

    力扣链接: 力扣 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

    2024年02月12日
    浏览(29)
  • 代码随想录打卡第35天

    2024年02月12日
    浏览(23)
  • 代码随想录打卡第34天

    2024年02月11日
    浏览(77)
  • 代码随想录补打卡 56 合并区间

    56 合并区间  代码如下 func merge(intervals [][]int) [][]int {         sort.Slice(intervals,func(i,j int)bool{  //将数组按左边界的大小排序         return intervals[i][0]intervals[j][0]     })     res := make([][]int,0) //定义一个目标数组     res = append(res,intervals[0])  //先将数组的第

    2024年02月02日
    浏览(30)
  • 代码随想录第41天 | 动态规划part03

    ● 343. 整数拆分 ● 96.不同的二叉搜索树 题目一 343. 整数拆分 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 : 输入: 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。 说明: 你可以假设 n 不小于 2 且不大于 5

    2024年01月24日
    浏览(38)
  • 代码随想录打卡第56天|583. 两个字符串的删除操作;72. 编辑距离

    583. 两个字符串的删除操作 关键点1:dp数组的含义 dp[i][j],使得以i-1为结尾word1 和 以j-1为结尾的word2 相同所需的最小步数; 关键点2:递归公式的推导 if(nums1[i-1] == nums2[j-1]),则i和j同时移动,所以为i-1,j-1;dp[i][j] = dp[i-1][j-1];由于不需要进行删除操作,所以不需要加1 如果不相

    2023年04月19日
    浏览(37)
  • 代码随想录day44

    完全背包 其实就是每个物品可以使用无数次,给我们一个容器,装满这个容器的最大价值是多少。 思路: 如果求组合数就是外层for循环遍历物品,内层for遍历背包。 如果求排列数就是外层for遍历背包,内层for循环遍历物品。 完全背包的组合和排序 518. 零钱兑换 II 题目 给你

    2023年04月17日
    浏览(39)
  • 代码随想录day59

    647. 回文子串 给你一个字符串  s  ,请你统计并返回这个字符串中  回文子串  的数目。 回文字符串  是正着读和倒过来读一样的字符串。 子字符串  是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不

    2024年02月07日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包