剑指offer-66.剪绳子

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxm1306192988/article/details/82055899

LeetCode

题目描述

把一根绳子剪成多段,并且使得每段的长度乘积最大。

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

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

题解:
方法一:贪心

尽可能多剪长度为 3 的绳子,并且不允许有长度为 1 的绳子出现。如果出现了,就从已经切好长度为 3 的绳子中拿出一段与长度为 1 的绳子重新组合,把它们切成两段长度为 2 的绳子。
这样可以使乘积最大。

证明:
当 n>5 时, 3(n - 3) - 2(n - 2) = n - 5 >= 0。
因此把长度大于 5 的绳子切成两段,令其中一段长度为 3 可以使得两段的乘积最大。

class Solution {
    public int integerBreak(int n) {
        if (n < 2)
            return 0;
        if (n == 2)
            return 1;
        if (n == 3)
            return 2;
        int timesOf3 = n / 3; //计算 3的个数
        if (n - timesOf3 * 3 == 1) //如果最后出现长度为1的绳子,
            timesOf3--; //就从已经切好长度为 3 的绳子中拿出一段与长度为 1 的绳子重新组合
        int timesOf2 = (n - timesOf3 * 3) / 2; //把它们切成两段长度为 2 的绳子
        return (int) (Math.pow(3, timesOf3)) * (int) (Math.pow(2, timesOf2));
    }
}

方法二:动态规划
定义函数f(n)为把长度为n的绳子剪成若干段后各段长度乘积的最大值。
在剪第一刀时,我们有n-1种选择,也就是说第一段绳子的可能长度分别为1,2,3…..,n-1。
因此f(n)=max(f(i)*f(n-i)),其中0 < i < n。
这是一个自上而下的递归公式。由于递归会有大量的不必要的重复计算。一个更好的办法是按照从下而上的顺序计算,也就是说我们先得到f(2),f(3),再得到f(4),f(5),直到得到f(n)。

当绳子的长度为2的时候,只能剪成长度为1的两段,所以f(2) = 1,当n = 3时,容易得出f(3) = 2;

class Solution {
    public int integerBreak(int n) {
        if (n < 2)
            return 0;
        if (n == 2)
            return 1;
        if (n == 3)
            return 2;
        int[] f = new int[n + 1];
        f[0] = 0;
        f[1] = 1;
        f[2] = 2;
        f[3] = 3;
        int result = 0;
        for (int i = 4; i <= n; i++) {
            int max = 0;
            for (int j = 1; j <= i / 2; j++) {
                int num = f[j] * f[i - j];
                if (num > max) {
                    max = num;
                }
            }
            f[i] = max;
        }
        return f[n];
    }
}

猜你喜欢

转载自blog.csdn.net/zxm1306192988/article/details/82055899