动态规划 - 整数拆分

对于动态规划的思路,在这就不多说了,需要理解的看下这一篇文章动态规划步骤​​​​​​,

下面直接进入主题,利用动态规划思路来解决343. 整数拆分 - 力扣(LeetCode)。

动态规划 - 整数拆分_第1张图片

第一步、确定数组dp,创建保存整数拆分之后得到的最大乘积的数组。

# 确定数组的长度,每次拆分的计算结果是为上一次的最大乘积,作为占位符。
dp = [0] * (n+1)  

第二步、确定数组dp的初始值。

从题中可以知道2 \leqslant n \leqslant 58,所以在拆分 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数组保存每一个整数拆分得到的最大乘积的值。

动态规划 - 整数拆分_第2张图片

需要注意几个问题,

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))

你可能感兴趣的:(动态规划,算法)