[343. 整数拆分]
「这是我参与2022首次更文挑战的第35天,活动详情查看:2022首次更文挑战」。
题目描述
给定一个正整数 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
思路
这是一道 动态规划 的题。判定一道题使用动态规划的标准是看当前状态是否依赖之前的状态,即问题由许多重复的子问题组成,一个数可以看成多个数字相乘而成,在进行下一个数时,可以借助之前的拆分结果。这道题的子问题判定为是之后有以下几个步骤:
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
具体到这道题:
1、dp数组含义:拆分和为i的最大乘积为dp[i]。
2、递推公式:可以将i拆分为两数:j和i-j,乘积为j*(i-j),也可以在拆出j后,对i-j再进行拆分,那么乘积就是j*dp[i-j] 其中的dp[i-j]即为拆分和为i-j的最大乘积,通过不断的尝试拆j,取最大值,即dp[i]=max(j*(i-j),j*dp[i-j]) ;
3 、初始化:按照题目的意思,i<2时。不需要初始化,那么需要初始化第一个值dp[2]=1。
4、遍历顺序:依赖之前的状态,即从前往后遍历。
5、 0,0,1,2,4,6....(dp[0],dp[1]无意义)
代码实现
细节见注释
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n+1);
dp[2]=1; //初始化
for(int i=3;i<=n;++i){ //从3开始
for(int j=1;j<i-1;++j){ //从1开始拆,拆至i-j==2,因为i-j<2时,i-j不可拆
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j])); //递推公式
}
}
return dp[n];
}
};
总结
简要的介绍了动态规划,动态规划的一般做题步骤等等。