CS-Notes全部笔记在阅读器中打开

14. 剪绳子

题目链接

Leetcode

题目描述

把一根长度为 n 的绳子剪成多段(至少剪一刀,n ≥ 2),每段长度为整数,求各段长度乘积的最大值。

n = 2
return 1 (2 = 1 + 1)

n = 10
return 36 (10 = 3 + 3 + 4)

解题思路

贪心

结论:尽可能多剪长度为 3 的段;剩下 1 时,把一个 3 + 1 改成 2 + 2;剩下 2 时,单独留一段 2。例如 n = 10 = 3 + 3 + 4,乘积 3 × 3 × 4 = 36。

推导分三步:

所以 n 除以 3 余 0 时全是 3;余 1 时最后是 2 + 2;余 2 时最后是一个 2。n = 2、3 时必须至少剪一刀,答案分别是 1 和 2,要单独处理。

public int cuttingBamboo(int bamboo_len) {
    if (bamboo_len < 2)
        return 0;
    if (bamboo_len == 2)
        return 1;
    if (bamboo_len == 3)
        return 2;
    int timesOf3 = bamboo_len / 3;
    if (bamboo_len - timesOf3 * 3 == 1)
        timesOf3--;
    int timesOf2 = (bamboo_len - timesOf3 * 3) / 2;
    return (int) (Math.pow(3, timesOf3)) * (int) (Math.pow(2, timesOf2));
}

动态规划

dp[i] 表示长度为 i 的绳子剪过至少一刀后的最大乘积。枚举最后一段的长度 i - j,前面的 j 不再剪时乘积为 j × (i - j),继续剪时为 dp[j] × (i - j),取最大值。时间复杂度 O(N2)。

public int cuttingBamboo(int bamboo_len) {
    int[] dp = new int[bamboo_len + 1];
    dp[1] = 1;
    for (int i = 2; i <= bamboo_len; i++)
        for (int j = 1; j < i; j++)
            dp[i] = Math.max(dp[i], Math.max(j * (i - j), dp[j] * (i - j)));
    return dp[bamboo_len];
}

在阅读器中可以用目录和搜索、切换深色模式、练习这篇笔记中的面试题:打开《14. 剪绳子》