题目:一段绳子长度为n(n>1),至少剪一次,问每段长度的乘积的最大值是多少?
public int cuttingRope(int n)
思路:当n=2,3,4,时单独分析,结果分别是1,2,4。
当n>=5时,2(n-2)>n,3(n-3)>n。意思是当n大于等于5时,剪一段为2,另一段为n-2,则它们的乘积更大。而3(n-3)>=2(n-2)所以应该尽量地以每段为3来剪。
实现为:n=3a+b; a=n/3; b=n%3 也就是有a段3。b只有0,1,2三种情况。当b=0时,结果为3a(用Math.pow)。当b=1时,结果为3(a-1)乘4,这是把最后的b=1和一个3弄成了2*2,变大,再加上前面的。当b=2时,结果为3a*2。
//没有大数运算的话,直接用n=3a+b,时间复杂度为O(1)
//Math.pow(a,b),a b为实数,时间复杂度为O(1)
public int cuttingRope(int n){
if(n <= 1){
return -999;
}else if(n <= 3){
return n-1;
}else if(n == 4){
return 4;
}
int a = n / 3;
int b = n % 3;
if(b == 0){
return (int)Math.pow(3,a);
}else if(b == 1){
return (int)Math.pow(3,a-1) * 4;
}else{
return (int)Math.pow(3,a) * 2;
}
}
剪绳子(大数运算):
题目相同,但是当n取很大时,分的段数a可能会导致指数3^a过大。
public int cuttingRope(int n)
先给面试官讲O(n)的while解法,再讲O(logn)的快速幂(指数二进制表示,最右端指针向左移动,求3^(n-1))的解法。
思路:1.使用while处理,n每次减3,直到小于5就结束。并说明正确性。时间复杂度:O(n)
正确性保证:n不会减到1,因为当n减到4时就结束了。当最后n=2,3,4时都满足条件。
//有大数运算,用while,并解释正确性,O(n)
public int cuttingRopeWithBigNum(int n){
if(n <= 1){
return -999;
}else if(n <= 3){
return n-1;
}else if(n == 4){
return 4;
}
long res = 1;
//n等于4时结束,所以n不会为1。所以n最后为4,3,2都满足条件
while(n > 4){
n -= 3;
res *= 3;
res %= 1000000007;
}
//注意最后把n乘上
return (int)((res*n)%1000000007);
}
2.快速幂的方法。
求a^b,把b用二进制分解,次数分成和的形式(一个初始指针在最右边,次数除2,指针就向左移动一格)。这样次数b可以一半的速度减小,就类似二分的思想,时间复杂度为O(logn)。
比如求a^10,10的二进制为1010,当次数为10时,它不是奇数,所以最右边那位为0。x则等于x*x。这样随着次数不断减小,x作为系数则正好吻合。这样当次数为0时就得到了结果。(这个过程就相当于初始一个指针在最右边,次数除2,就向左边移动一格。指针所指为1,也就是次数为奇数,最后的结果res就乘上不断变化且吻合的x系数)
注意:快速幂只能先求3(n-1)。而不能先求3^n,因为当b==1时要先除3再乘4,或者当多乘一个3后取余1000000007后就不是3的倍数了,再除3再乘4答案就不对了。
而先求3^(n-1)后,b的三种情况都直接乘一个数,所以不会出问题。
public int cuttingRopeWithBigNumByFastPower(int n){
if(n <= 1){
return -999;
}else if(n <= 3){
return n-1;
}else if(n == 4){
return 4;
}
int a = n / 3 - 1;
int b = n % 3;
long res = 1,x = 3;
//快速幂求3^(a-1)
//把a次幂用二进制拆开,通过a每次右移一位来看,来看它在这二进制位上是否为1,并用x从右往左计算
//用于后面res的相乘
//不能求3^a,是因为b除3再乘4(当b==1时),但是由于%了1000000007,所以算完不是3的倍数,所以会导致错误
//所以最后都弄成乘法就不会出错
while(a > 0){
if((a & 1) == 1) {
res = (res * x) % 1000000007;
}
x = (x * x) % 1000000007;
//除2是往右移动1位
a >>= 1;
}
if(b == 0){
return (int)(res * 3 % 1000000007);
}else if(b == 1){
return (int)((res * 4) % 1000000007);
}else{
return (int)((res * 6) % 1000000007);
}
}