目录

每日算法力扣343.整数差分动态规划

目录

每日算法:力扣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

分析:根据题目要求,一个数可被差分为它的子数,然后子数乘积中取最大值。

则当j <= i 时,有 i = j * (i-j);

那么,这样就是最优解了吗?显然,当数比较小时,这样一般是对的,但是当数比较大时呢?

那么,我们可以先从小的开始分析:

我们先设立一个dp数组,数组中用于存放每个数子数乘积的最大值。

则最小子问题为:

dp[1] = 1;

dp[2] = 1;

dp[3] = 2;

那么,从4开始,我们就需要开始差分了,并且,将每次的最大值保存到数组中,那么很显然,如果当前的j*(i-j)不是最大值,难么(i-j)这个数的最大值就被保存在dp[i-j]这个下标的数组中,因此我们可以取jdp[i-j];然后,取最大值,则有 dp[i] = max(dp[i],max(j(i-j),j*dp[i-j]));

至此,状态转移方程推导完毕。

代码:

class Solution {
public:
    int dp[100];
    int integerBreak(int n) {
    //预处理最小子问题
        dp[1] = 1;    
        dp[2] = 1;
        dp[3] = 2;
        for(int i = 4;i <= n;i++){//第一层循环,遍历1-n的所有数
            for(int j = 1;j <= i;j++){//第二层循环,遍历这个数可被差分的数
                dp[i] = max(dp[i],max(j*(i-j),j*dp[i-j]));//比较:当前的子数乘积和其继续差分的乘积,取最大值 
            }
        }
        return dp[n];
    }
};