剑指 Offer 14- II. 剪绳子 II
给你一根长度为 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
贪心法
结论:每次拆成n个3,如果剩下是4,则保留4,然后相乘,但是这个结论需要数学证明其合理性!k神的数学证明
- 当
n ≤ 3(2, 3)
时,按照规则应不切分,但由于题目要求必须剪成m>1
段,因此必须剪出一段长度为1
的绳子,即返回n−1
- 当
n = 4
时,可以拆分成2+2
,返回结果2*2=4
- 当
n >4
时,减掉多个3之后剩下的n=2, 3, 4
, 因为2、3不需要再剪了(剪了反而变小);4剪成2x2是最大的,2x2恰巧等于4一个优秀的解释
注意res对1000000007取余一次,最后的结果也要取余。
class Solution {
public:
int cuttingRope(int n) {
if(n <= 3) return n - 1;
if(n == 4) return 4;
long res = 1, p = 1000000007;
while(n > 4){
res *= 3;
res %= p;
n -= 3;
}
// 最后n的值只有可能是:2、3、4。而2、3、4能得到的最大乘积恰恰就是自身值
// 因为2、3不需要再剪了(剪了反而变小);4剪成2x2是最大的,2x2恰巧等于4
return n * res % p;
}
};