题目描述
给你一根长度为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。
题解:
边界要注意一下,因为题目要求一定要分成至少两段,故,当n=1 ->1*0; n=2 -> 1*1; n=3 -> 2*1
两种方法进行求解
动态规划:
首先定义函数(n)为把长度为n的绳子剪成若干段后各段长度乘积的最大值。在剪第一刀的时候,我们有n-1种可能的选择,也就是剪出来的第一段绳子的可能长度分别为1,2….n-1。因此f(n) = max(f(i) * f(n-i))。
1 class Solution { 2 public: 3 int cutRope(int number) { 4 if (number <= 1)return 0; 5 if (number < 5)return (number / 2)*(number - number / 2);//因为至少要分为2段 6 vector<int>dp(number + 1, 0); 7 dp[0] = 0, dp[1] = 1, dp[2] = 2, dp[3] = 3; 8 int maxN = 0; 9 for (int i = 4; i <= number; ++i) 10 { 11 maxN = 0; 12 for (int j = 1; j <= i / 2; ++j) 13 { 14 int temp = dp[j] * dp[i - j]; 15 maxN = maxN > temp ? maxN : temp; 16 dp[i] = maxN; 17 } 18 } 19 return dp[number]; 20 } 21 };
贪婪算法:
如果我们按照如下的策略来剪绳子,则得到的各段绳子的长度的乘积将最大:当n≥5时,我们尽可能多地剪长度为3的绳子;当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子。
为什么要剪成3,这是个数学证明,详细请看书
1 class Solution { 2 public: 3 int cutRope(int number) { 4 if (number <= 1)return 0; 5 if (number < 5)return (number / 2)*(number - number / 2);//因为至少要分为2段 6 int n3 = number / 3;//3的个数 7 if (number % 3 == 1)//最后剪的一段为4时,不要剪成3-1,要剪成2-2 8 n3--; 9 int n2 = (number - 3 * n3) / 2;//2的个数 10 return pow(3, n3)*pow(2, n2); 11 } 12 };