持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题。
整数拆分
给定一个正整数 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。
暴力搜索
对于给定的一个整数 n
,穷举它的每一种分解情况,然后对所有情况,求最大值。
fun integerBreak(n: Int): Int {
if (n == 2) {
return 1
}
var res = -1
for (i in 1..n - 1) {
res = Math.max(res, Math.max(i * (n - i), i * integerBreak1(n - i)))
}
return res
}
动态规划
令dp[i]表示整数i对应的最大乘积,那么dp[i]的值应是dp[j]×(i-j),j属于[1,i-1]的最大值,同时注意dp[i]对应的值是经过拆分了的,所以还应判断两个数拆分的情况,即j*(i-j)的值,取最大即可。
fun integerBreak(n: Int): Int {
if (n <= 3) {
return n - 1
}
val dp = IntArray(n + 1)
dp[2] = 1
for (i in 3..n) {
dp[i] = (2 * (i - 2)).coerceAtLeast(2 * dp[i - 2]).coerceAtLeast((3 * (i - 3)).coerceAtLeast(3 * dp[i - 3]))
}
return dp[n]
}
数学
当我们多写几组数据推导就会发下以下规律:
- 若拆分的数量 a 确定, 则各拆分数字相等时,乘积最大。
- 将数字 n 尽可能以因子 3 等分时,乘积最大。
所以我们可以把数字 n 尽可能拆为多个因子 3 ,余数可能为0,1,2 三种情况,若余数为 2,则保留,不再拆为 1+1,若余数为 1,则应把一份 3 + 1 替换为 2+2,因为 2×2>3×1。
代码如下:
fun integerBreak(n: Int): Int {
if (n <= 3) return n - 1
val a = n / 3
val b = n % 3
if (b == 0) return 3.0.pow(a.toDouble()).toInt()
return if (b == 1) 3.0.pow((a - 1).toDouble()).toInt() * 4 else 3.0.pow(a.toDouble()).toInt() * 2
}