剑指offer 面试题. 剪绳子

题目描述

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

猜你喜欢

转载自www.cnblogs.com/FdWzy/p/12310084.html