[菜鸟训练]剑指 Offer 14. 剪绳子

题目描述:

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 58
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

我们假设将其分为m份,则题目的要求就是求
MAX(a(1)a(2)a(m))
已知,n=a(1)+a(2)+…+a(m)

那么当我们怎样截取时才能使截取后各段长度相乘最大呢?
通过算数几何均值不等式我们可知:
引自他人

当我们将其以相同的长度分为多段的时候乘积最大。
当然这里不能全部分为1的小段。

那我们不妨假设每一段都是等长的,且不为1。

在这里插入图片描述

通过上面的证明我们知道当我们每次都去切长度3的小段时,最后得到的乘积最大。但是现实却是我们最后并不一定能全部等份切割,所以这里就有了三种情况,即最后一段是长度为0、1、2的情况:
(1)长度为0,最完美的情况,分为了m个长度为3的小绳
(2)长度 为1,任何数乘1都为自己本身,不会变大,所以我们不如将1和前一段3合并,这样得到的乘积将会是最大
(3)长度为2,此时我们没办法再分了,直接乘即可。

注意:这主要就是一个贪心的思想,每次都去找局部最优解。
感觉dp也可以写,后继补充

代码:

public class jianzhi_Offer_14_1 {
    
    
    public int cuttingRope(int n) {
    
    
        if(n == 2){
    
    
            return 1;
        }
        if(n == 3){
    
    
            return 2;
        }
        if (n == 4){
    
    
            return 4;
        }
        int ans = 1;
        int tmp;
        int num = n;
        while (num >= 3){
    
    
            if((num - 3) >= 3){
    
    
                ans *= 3;
                num -= 3;
            }
            else if((num - 3) == 1){
    
    
                ans *= 4;
                num -= 4;
                break;
            }
            else if((num - 3) == 2){
    
    
                ans *= 6;
                num -= 5;
                break;
            }
            else if((num - 3) == 0){
    
    
                ans *= 3;
                num -= 3;
                break;
            }

        }
        return ans;
    }

    public static void main(String[] args) {
    
    
        jianzhi_Offer_14_1 obj = new jianzhi_Offer_14_1();
        System.out.println(obj.cuttingRope(9));
    }
}

题目描述:

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1] 。请问 k[0]k[1]…*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

提示:
2 <= n <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

该题目和前者的区别就是,n的取值范围变大了,这就意味着我们最终得到的答案会超过int所能承受的最大极限。这时候我们就可以使用取余的分配性:
(a * b) % m = ((a%m)*(b%m)) % m
再加上循环取余就可以解决该问题。(因为,可能在中间相乘的过程中就会超限,所以我们需要相乘一下就对结果取余)

代码:

public class jianzhi_Offer_14_2 {
    
    
    public int cuttingRope(int n) {
    
    
        int modnum = 1000000007;
        if(n == 2){
    
    
            return 1;
        }
        if(n == 3){
    
    
            return 2;
        }
        if (n == 4){
    
    
            return 4;
        }
        //注意这里要使用long
        long ans = 1;
        int tmp;
        int num = n;
        while (num >= 3){
    
    
            ans = ans % modnum;
            if((num - 3) >= 3){
    
    
                ans = (ans * 3) % modnum;
                num -= 3;
            }
            else if((num - 3) == 1){
    
    
                ans = (ans * 4) % modnum;
                num -= 4;
                break;
            }
            else if((num - 3) == 2){
    
    
                ans = (ans * 6) % modnum;
                num -= 5;
                break;
            }
            else if((num - 3) == 0){
    
    
                ans = (ans * 3) % modnum;
                num -= 3;
                break;
            }

        }
        if( ans == modnum + 1)
            return 1;
        return (int)ans;
    }

    public static void main(String[] args) {
    
    
        jianzhi_Offer_14_2 obj = new jianzhi_Offer_14_2();
        System.out.println(obj.cuttingRope(120));
    }
}

猜你喜欢

转载自blog.csdn.net/Puppet__/article/details/115076052