剑指Offer_#14-2_剪绳子

剑指Offer_#14-2_剪绳子

Contents

题目

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m] 。请问k[0]*k[1]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是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

思路分析

和前一题相比,唯一的区别就是这里的输入范围变大的,所以导致最后的结果可能会超过int所表示的最大范围,所以需要考虑如何求这个大数的余数。
我觉得这个题更像是一道数学题,而不是什么动态规划...

题解1

这是二分求余数法,其实我不完全理解,为什么遇到奇数需要特殊处理,之后再多看几遍吧。

class Solution {
    public int cuttingRope(int n) {
        if(n <= 3) return n-1;
        int b = n % 3,p = 1000000007;
        long rem = 1,x = 3;
        for(int a = n/3 - 1;a > 0;a /= 2){//a的初始值为什么是n/3-1?这是长度为3的绳子段数。循环过程就是计算3^a%p
            if(a % 2 == 1) rem = (rem * x) % p;//逢奇数,需要特殊处理
            x = (x * x) % p;
        }
        if(b == 0) return (int)(rem * 3 % p);
        if(b == 1) return (int)(rem * 4 % p);
        return (int)(rem * 6 % p);//不理解为什么乘以6?
    }
}

复杂度分析

由于每次指数减小一倍,时间复杂度是

题解2

贪心算法,也就是直接分析出每一次都是剪下长度为3的绳子最好,所以直接通过循环模拟这个过程,每次绳子长度减小3,结果乘以3。
循环结束的结果分为三种:
1.n=2,等于说无限除以3,最后余下绳子长度为2,此时将res乘以2即可
2.n=3,绳子全部用完,直接所有3相乘即可
3.n=4,等于说余下绳子长度为1,因为4%3=1,但是3<2*2,也就是4本身,故最后乘4
这里的求余方式是循环求余,复杂度稍高,但是更加直观。
循环求余法的依据是

也就是说,每一轮都进行一次求余操作,再迭代,和先迭代完成后再进行求余操作,结果相同。

class Solution {
    public int cuttingRope(int n) {
        if(n<=3) return n-1;
        long res=1;
        while(n>4){
            res*=3;
            res=res%1000000007;
            n-=3;
        }
        return (int)(res*n%1000000007);
    }
}

复杂度分析

相比二分求余法,这个方法的复杂度稍高,是

扫描二维码关注公众号,回复: 11319643 查看本文章

猜你喜欢

转载自www.cnblogs.com/Howfars/p/13166859.html