对于动态规划的思路,在这就不多说了,需要理解的看下这一篇文章动态规划步骤,
下面直接进入主题,利用动态规划思路来解决343. 整数拆分 - 力扣(LeetCode)。
第一步、确定数组dp,创建保存整数拆分之后得到的最大乘积的数组。
# 确定数组的长度,每次拆分的计算结果是为上一次的最大乘积,作为占位符。
dp = [0] * (n+1)
第二步、确定数组dp的初始值。
从题中可以知道,所以在拆分 n == 0 or n == 1, 是没有意义的,很显然,我们拆分n == 2时,可以得出2 = 1 + 1,所以最大乘积为1, 即dp[2] = 1,后续的计算乘积结果也是基于dp[2]的结果。
dp[2] = 1
第三步、确定状态转移方程。dp[i] = max(dp[i], j * (i-j), j * dp[i - j])
我们可以通过一个简单实例来解释一下,当 n = 5时,dp数组保存每一个整数拆分得到的最大乘积的值。
需要注意几个问题,
1、拆分问题:我们需要拆分整数两个或两个以上的整数进行相加等于原数,且拆分后的数值相乘得到的乘积最大。所以需要考虑拆分两个正整数之后拆分和不拆分,
1)将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j * dp[i-j],此时,我们就需要dp数组中之前的值进行调用。
2、j 是从1 开始遍历,i-j 可以这么理解就是将需要拆分的n的数值减去对应的 j 的遍历值,
j * (i - j)也就是拆分两个整数的乘积。
3、我们需要比较 j * (i - j),j * dp[i-j]的乘积的最大。
所以,状态转移方程为:dp[i] = dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));
for i in range(3, n + 1):
for j in range(1, i - 1):
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
第四步、确定遍历顺序。
dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历,i是从3开始,枚举j的时候,是从1开始的。这样dp[i - j]就是dp[2]正好可以通过我们初始化的数值求出来。
第五步,用 n = 5举例,可以通过上表进行推导。
python代码展示:
def integerBreak(n):
dp = [0] * (n + 1)
dp[2] = 1
for i in range(3, n + 1):
for j in range(1, i - 1):
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
return dp[n]
print(integerBreak(5))