LeetCode 剪绳子

给你一根长度为 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

数学推导:
给出一个长度n,并且x1 + x2 + x3 +…+xn= n,那么这时候需要求解x1x2x3*…xn的最大值即可。那么怎么求解呢?
我们高中的时候学过不等式(x + y) / 2 >= √(xy),所以xy的最大值就是在x = y的时候,xy有最大值。所以我们这里就可以将这个性质应用到这里。所以在已知这些数的和已知的情况下,将绳子剪成等长可以使得最后结果的乘积最大。所以关键怎么知道要将绳子剪多长?
请看下面的证明过程:
在这里插入图片描述
绳子总长大于3的时候,需要将绳子剪成div分等长的并且长度为3的绳子。已经知道了将绳子剪成等长3的时候,我们需要分3中情况讨论:
①当绳子刚好整除3,那么最后的结果就是3 ^ div
②当绳子不能整数3的时候,并且余数为1,那么这时候我们需要将一份长度为3的绳子保留,这时候就剩下div - 1分长度为3的等长绳子和1分长度为4的绳子。这时候将这个长度为4的绳子剪成2 + 2的绳子,才会有最大值。此时最大值为3 ^(div - 1) * 4.
③当余数为2的时候,不需要将2这个绳子再进行分割,而是保留。此时最大值为3 ^ div * 2.

对应的代码:

class Solution {
    public int cuttingRope(int n) {
       if(n == 2)
          return 1;
       if(n == 3)
          return 2;
       int div = n / 3;//将n分成等3长度
       int result = (int)Math.pow(3,div);
       //System.out.println(div + ", " + result);
       if(n % 3 == 1){
           return (result / 3 )  * 4;//如果不能整除3,那么就将最后一份3加1化成2 * 2
       }else if(n % 3 == 2){
           //如果最后还剩下2,那么就将这个2直接保留,而不是将2化成1+1
           return result * 2;
       }else{
           return result;//整除3的时候
       }
    }
    
}

运行结果:
在这里插入图片描述

给你一根长度为 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

基于上面的题目,我们来解决这个问题。但是如果是只是上面的代码的结果result % 1000000007的话,那么就会发生报错,为什么?因为如果测试的例子是100的时候,最后返回的是一个负数,说明发生了越界。所以为了避免这个问题,我们需要不断取余。因此这个题目还考察了大数取余。所以在取余的时候,还需要了解这个公式:
(x \* y) % p = [(x % p) \* (y % p)] %p,刚开始我对这个公式感到疑惑的是,为什么最后还需要[x %p][y %p]这个数在模p呢?后来通过距离例子可以证明:如果p = 6,x * y = 6,假设x = 2, y = 3,那么如果最后没有在模6的话,那么[2 % 6][3 % 6] = 6,而不是我们想要的0,因此最后还要再模p。

对应的代码:

class Solution {
    public int cuttingRope(int n) {
       if(n <= 3) 
          return n - 1;
        long div = n / 3,num;//这个绳子能分成3的多少分
        long res = 1;
        num = div - 1; //为了避免存在最后剩余长度为1的情况,所以先计算div - 1等长的积对1000000007的模
        //循环取模法
        while(num > 0){
            res = (res * 3) % 1000000007;
            num--;
        }
        if(n % 3 == 1){
            //如果最后余1,那么需要取3的div - 1次方,最后4分成2 * 2
            res = (res * 4) % 1000000007; 
        }else if(n % 3 == 2){
        /*
        注意这里不可以是(res * 3 * 2) % 1000000007,因为有可能res * 3之后
        大于了1000000007
        */
            res = (((res * 3) % 1000000007) * 2) % 1000000007;
        }else{
        //刚好整除的时候,那么需要乘以3,将最后一份长度为3的绳子相乘
            res = (res * 3) % 1000000007;
        }
        return (int)res;
        
    }

}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值