力扣343——整数拆分(动态规划,数学)

题目描述(中等)

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

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

示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。

思路1:动态规划

首先把边界判断掉,2返回2,3返回3;
对于后面的数,通过观察,4时的结果是13,112,1111,22,211,31中的最大值
令1时最优解为1,2时最优解为2,3时最优解为3,那4的最优解相当于13,22,31中最大值,即4
对于5,其结果为1(4时最优解),2*(3时最优解),3*(2时最优解),4*(1时最优解)中的最大值,即6
对于6,其结果为1*(5时最优解),2*(4时最优解),3*(3时最优解),4*(2时最优解),5*(1时最优解)中的最大值,即9
后面的结果由前面的结果运算得到,且前面结果不受后面数的影响,动态规划实锤
dp[i]定义为i时最优解(i>=4)
对于数n,将其拆分为至少两个正整数的和,我们假设拆分为x+y,如果要继续拆分y,那此时结果为xdp[y];如果要继续拆分x,同理ydp[x];如果都要拆分,问题其实就是将n拆分为x1和(x1+y1+y2)这样的组合。
所以遍历n拆分为两项的所有组合,即可考虑所有组合
递推公式为dp[i] = max(dp[i],dp[j]*(i-j));其中j从i-1到1遍历
由于要乘积最大,所以拆分组合带1肯定不会是最优解,j可以从i-2到2进行遍历,减少不必要计算。

需要注意的就是,边界值并不是dp里面的最优解,虽然2时最优解为1,但dp[2]初始为2;dp[3]同理

代码

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

思路2:数学

复杂的公式推导详见官方题解
比较清晰的推导过程详见大佬题解
主要是均值不等式的运用,当每个拆分的小块取 x 1 x x^{\frac{1}{x}} xx1时乘积才能最大,而 x 1 x x^{\frac{1}{x}} xx1的极大值取在e=2.71828…
而本题只能取整数,所以就在2、3之间,而且口算可知 3 ∗ 3 > 2 ∗ 2 ∗ 2 3*3>2*2*2 33>222,所以能选3就选3,选不了3就选2。
其实自己写的过程中也发现,最大的结果都是几个2、3的相乘。

数学思路的简单推理:
对于 n >= 4,拆分后总是收益更大,因此最终所有 >= 4 的数都可以拆分为 2,3的组合(当然不可能有1)。
而 2*2*2 < 3*3 ,2*2 > 3*1 ;因此拆分后所有的 2 三个一组合并为 3*3,剩下的2保留,最后计算乘积即可。

代码

class Solution {
public:
    int integerBreak(int n) {
        if (n <= 3) {
            return n - 1;
        }
        int quotient = n / 3;
        int remainder = n % 3;
        if (remainder == 0) {
            return (int)pow(3, quotient);
        } else if (remainder == 1) {
            return (int)pow(3, quotient - 1) * 4;
        } else {
            return (int)pow(3, quotient) * 2;
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
左程云在动态规划题型方面有一些相关的讲解和课程。动态规划是一种常见的算法设计技巧,可以解决一些具有重叠子问题性质的问题。通过分解问题为子问题,然后根据子问题的解推导出原问题的解。引用中提到了左程云的算法课堂上有动态规划相关的题目。还有一些其他的题目也可以在LeetCode上找到,比如[1108. IP 地址无效化(简单)]、[344. 反转字符串(简单)]以及[剑指 Offer 58 - I. 翻转单词顺序(简单)]等。所以,如果对动态规划感兴趣,可以参考左程云的课堂和LeetCode上的相关题目进行练习。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [出自算法之神“左程云”的这本《算法面试指南》被LeetCode官推,秀我一脸~](https://blog.csdn.net/SharingOfficer/article/details/121523204)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [左程云leetcode-LeetCode:力扣解决方案](https://download.csdn.net/download/weixin_38556416/19925757)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值