题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。请问k[0]xk[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
解答:
方法1:
使用动态规划。对于n,可以切为1和n-1,2和n-2.......等等。即递推方程为for(i=1~n-1),dp[n]=max(dp[n-i]*dp[i],dp[n])
但此题有个要求是m>1,即不能不切,这对小于4的数有影响。2只能切一刀,1*1=1。3切一刀1*2=2。4最大2*2=4,5最大2*3=6,即之后的n分割的乘积就大于等于n自己了。
所以对于小于4的n单独返回,其他n动态规划解决。
1 class Solution { 2 public: 3 int cutRope(int number) { 4 if(number==2){return 1;} 5 if(number==3){return 2;} 6 vector<int> dp(number+1,INT_MIN); 7 dp[1]=1,dp[2]=2,dp[3]=3,dp[4]=4; 8 for(int i=5;i<=number;++i){ 9 for(int j=1;j<i;++j){//至少切一刀 10 dp[i]=max(dp[i-j]*dp[j],dp[i]); 11 } 12 cout<<i<<" "<<dp[i]<<endl; 13 } 14 return dp[number]; 15 } 16 };
方法2:
还有一种数学方法,从评论区看到的。是说对于所有的n(n>=4),其最大分割的乘积值都是由2和3乘起来得到的。
来自评论区offer已确定,还差个对象。的思路和代码:
如:
4 : 2*2
5 : 2*3
6 : 3*3
7 : 2*2*3 或者4*3
8 : 2*3*3
9 : 3*3*3
10:2*2*3*3 或者4*3*3
11:2*3*3*3
12:3*3*3*3
13:2*2*3*3*3 或者4*3*3*3
另外不可能有超过两个2出现在结果中。因为3个2的和为6,6可以分解为两个3,3*3=9,2*2*2=8,9>8,所以不可能分割为3个2。
所以首先我们尽量找更多的3,即n/3个3。如果n%3==1,那么只能少拿一个3,和余的1一起分割成两个2。如7%3==1,那么最大=3*2*2
如果n%3==2,那么直接2*pow(2,n/3)。如8%3==2,最大=2*pow(3,8/3)
代码:
1 long long n_max_3(long long n) { 2 if (n == 2) { 3 return 1; 4 } 5 if (n == 3) { 6 return 2; 7 } 8 long long x = n % 3; 9 long long y = n / 3; 10 if (x == 0) { 11 return pow(3, y); 12 } else if (x == 1) { 13 return 2 * 2 * (long long) pow(3, y - 1); 14 } else { 15 return 2 * (long long) pow(3, y); 16 } 17 }