题目描述
给你一根长度为 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。
输入描述
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:2 <= n <= 58
思路描述
思路1 贪心算法
题目中
n
=
a
1
+
a
2
+
.
.
.
+
a
m
n = a_1+a_2+...+a_m
n=a1+a2+...+am,求
a
1
∗
a
2
∗
.
.
.
∗
a
m
a_1*a_2*...*a_m
a1∗a2∗...∗am的最大值。根据算术平均不等式可知:
a
1
+
a
2
+
.
.
.
+
a
m
m
≥
a
1
∗
a
2
∗
.
.
.
∗
a
m
m
{a_1+a_2+...+a_m \over m} \geq \sqrt [m]{a_1*a_2*...*a_m}
ma1+a2+...+am≥ma1∗a2∗...∗am
当且仅当
a
1
=
a
2
=
a
3
=
.
.
.
=
a
m
=
n
m
a_1 = a_2 = a_3 = ... = a_m = {n \over m}
a1=a2=a3=...=am=mn,假设
n
=
a
x
n = ax
n=ax,那么乘积为
x
a
x^a
xa,即将n等分成a个x段的绳子的乘积是
x
a
x^a
xa,
x
a
=
x
n
x
=
(
x
1
x
)
n
x^a = x^{\frac {n}{x}} = (x^{\frac {1}{x}})^n
xa=xxn=(xx1)n已知n为常数,那么,令
y
=
x
1
x
y = x^{\frac {1}{x}}
y=xx1取使得y最大的x值,对y进行求导如下:
l
n
y
=
1
x
l
n
x
,
两
边
同
时
取
l
n
lny = {1 \over x}lnx,两边同时取ln
lny=x1lnx,两边同时取ln
1
y
y
′
=
1
−
l
n
x
x
2
,
两
边
同
时
求
导
数
{1 \over y}y' = {1-lnx \over x^2},两边同时求导数
y1y′=x21−lnx,两边同时求导数
y
′
=
1
−
l
n
x
x
2
x
1
x
,
当
x
=
e
时
,
y
′
=
0
y' = {1-lnx \over x^2} x^{\frac {1}{x}},当x = e时,y' = 0
y′=x21−lnxxx1,当x=e时,y′=0
易知e是y的极大值点,
e
≈
2.71328
e \approx 2.71328
e≈2.71328,因此将n分成由2和3组成的数最好,是2还是3,将2和3代入公式可知
2
1
2
<
3
1
3
2^{1 \over 2} < 3^{1 \over 3}
221<331,因此能分成3的尽量都分成3,但是有一个特例因为1是极差的选择,因此,对于长度为4的绳子应分成22而不是13,因此下面就分成三种情况进行讨论,
n
=
3
a
+
b
n = 3^a+b
n=3a+b,
n
=
2
n=2
n=2和
n
=
3
n=3
n=3单独讨论,因此题目要求必须至少分成2段,
n
=
2
n=2
n=2时,返回1,
n
=
3
n=3
n=3时,返回2,其他情况按照
n
=
3
a
+
b
n = 3^a+b
n=3a+b讨论:
- 当b=0时,返回pow(3,a);
- 当b=1时,返回pow(3,a-1)*4,要拿出一个3和1组成2*2;
- 当b=2时,返回pow(3,a)*2。
class Solution {
public:
int cuttingRope(int n) {
if(n==2) return 1;
if(n==3) return 2;
int left = n%3;
int times = n/3;
if(left==0) return pow(3,times);
if(left==1) return pow(3,times-1)*4;
else return pow(3,times)*2;
}
};
思路2 动态规划解法
- 我们想要求长度为n的绳子剪掉后的最大乘积,可以从前面比n小的绳子转移而来
- 用一个dp数组记录从0到n长度的绳子剪掉后的最大乘积,也就是dp[i]表示长度为i的绳子剪成m段后的最大乘积,初始化dp[2] = 1
- 我们先把绳子剪掉第一段(长度为j),如果只剪掉长度为1,对最后的乘积无任何增益,所以从长度为2开始剪
- 剪了第一段后,剩下 ( i − j ) (i - j) (i−j)长度可以剪也可以不剪。如果不剪的话长度乘积即为 j ∗ ( i − j ) j * (i - j) j∗(i−j);如果剪的话长度乘积即为 j ∗ d p [ i − j ] j * dp[i - j] j∗dp[i−j]。取两者最大值 m a x ( j ∗ ( i − j ) , j ∗ d p [ i − j ] ) max(j * (i - j), j * dp[i - j]) max(j∗(i−j),j∗dp[i−j])
- 第一段长度j可以取的区间为
[
2
,
i
)
[2,i)
[2,i),对所有j不同的情况取最大值,因此最终dp[i]的转移方程为
d p [ i ] = m a x ( d p [ i ] , m a x ( j ∗ ( i − j ) , j ∗ d p [ i − j ] ) ) dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j])) dp[i]=max(dp[i],max(j∗(i−j),j∗dp[i−j])) - 最后返回dp[n]即可.