砍竹子 II
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 1312 ms, 内存: 16 MB
/*
* 题目思路:
* 将一根长度为 bamboo_len 的竹子分成若干段,每段的长度都是正整数。
* 我们需要找到分割方式,使得这些段的长度乘积最大。
* 可以利用动态规划来解决这个问题,dp[i] 表示将长度为 i 的竹子分割成若干段后的最大乘积。
* 递推公式为:dp[i] = max(j * (i - j), j * dp[i - j]),其中 j 从 1 遍历到 i-1。
* 使用 Java Stream 处理循环。
*/
import java.util.stream.IntStream;
public class BambooCuttingStream {
public static int maxProduct(int bamboo_len) {
int MOD = 1000000007;
int[] dp = new int[bamboo_len + 1];
dp[0] = 0;
dp[1] = 0;
for (int i = 2; i <= bamboo_len; i++) {
final int finalI = i;
dp[i] = IntStream.range(1, i).map(j -> Math.max(j * (finalI - j), j * dp[finalI - j])).max().orElse(0) % MOD;
}
return dp[bamboo_len];
}
public static void main(String[] args) {
System.out.println(maxProduct(12)); // 输出 81
}
}
解释
方法:
题解使用了自顶向下的动态规划方法,并利用记忆化来存储已经计算过的结果,避免重复计算,提高效率。函数dp(i)的作用是找到长度为i的竹子能得到的最大乘积。基本情况是当i等于2时,最大乘积为1。对于i大于2的情况,我们通过尝试每一种可能的第一段长度j(从2到i-1),计算两种情况的最大值:一是将竹子剩余部分继续切割得到的最大乘积(j * dp(i - j)),二是直接将竹子切成j和i-j两段(j * (i - j))。这两种情况的最大值,即为当前i的最大乘积。这样的递归确保我们可以从已解决的子问题构建出更大问题的解答。
时间复杂度:
O(n^2)
空间复杂度:
O(n)
代码细节讲解
🦆
在动态规划的实现中,为何选择自顶向下的方式而非自底向上?各有什么优缺点?
▷🦆
函数dp(i)中,为什么要比较`j * dp(i - j)`和`j * (i - j)`这两种情况?实际上这两种情况有什么区别?
▷🦆
在计算最大乘积时,为什么从2开始循环到i-1,将i本身作为一段的情况不被考虑?
▷🦆
在取模操作(% 1000000007)中,为什么要加这一步,直接返回dp(n)的结果会有什么问题?
▷