题目来源 Leetcode, 感谢🙇,如果内容对您有帮助,欢迎点赞。
题目描述
- 给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m] 。请问 k[0]*k[1]*…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
- 输入: 2
- 输出: 1
- 解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
- 输入: 10
- 输出: 36
- 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
- 2 <= n <= 58
解题思路
- 在经过一番思考之后,我觉得需要解决以下两个问题:
- 对于一段绳子如果分成 n 段,这 n 段怎么分最好?
- 如果一个绳子可以分成 1~n 段,那么选择分成几段最好呢?
- 对于分成 n 段怎么分的问题我们可以这么思考:
- 对于一个绳子分成两段怎么分最好,假设分的第一段为 x x x, 那么另一段为 n − x n-x n−x, 最好的分法转变为了求函数 f ( x ) = x ( n − x ) = − x 2 + n x f(x)=x(n-x)=-x^2 + nx f(x)=x(n−x)=−x2+nx 极值的问题,那么对于 f ( x ) f(x) f(x) 求导易得, x = 1 2 n x = \frac{1}{2} n x=21n。因此我们知道对于一段绳子而言我们最好的尽可能的均分,这样乘积最大。
- 更加严谨的数学证明可以描述为:算术均值一定大于几何均值,可由基本不等式 a + b 2 ≥ a b \frac{a+b}{2} \geq \sqrt{ab} 2a+b≥ab推广有: ( a 1 + a 2 + ⋯ + a n n ) n ≥ a 1 a 2 ⋯ a n (\frac{a_1+a_2 +\cdots+a_n}{n})^n \geq a_1a_2\cdots a_n (na1+a2+⋯+an)n≥a1a2⋯an
- 有了上式我们就知道如果分成n段我们该如何分:均分,有时候我们绝对均分,我们就要尽可能的均分,让所有段的方差最小,最接近均值。
- 那接下来就需要思考分成多少段最好了?
- 我在当时写代码的时候拍脑瓜简单一分析我觉得这个函数一定是一个先增后减函数(可举简单例子辅助思考),假定 f ( k ) f(k) f(k) 表示尽量均分k段后的乘积值,那么我们应该从 2 2 2 开始尝试直到找到这样一个 k k k,满足: f ( k − 1 ) ≤ f ( k ) ≥ f ( k + 1 ) f(k-1) \leq f(k) \geq f(k+1) f(k−1)≤f(k)≥f(k+1)
- 返回此时的 f ( k ) f(k) f(k),即为要求的最大值。
完整代码
class Solution {
public:
int cuttingRope(int n) {
int maxProduct = 0;
for(int i = 2; i <= n; ++i){
int average = n / i;
int rem = n % i;
int product = 1;
for(int j = 0; j < i; ++j){
if(rem != 0){
product *= (average + 1);
--rem;
}else
product *= average;
}
if(maxProduct < product)
maxProduct = product;
else
return maxProduct;
}
return maxProduct;
}
};
执行结果
进一步的推导思考
如果你耐心看到这里,实在感谢!🙇
- 虽然我们已经解决了问题,但是似乎还是不够完美,我们没有给出严整的数学证明过程,那么就就让我们尝试来写一写:
( a 1 + a 2 + ⋯ + a n n ) n ≥ a 1 a 2 ⋯ a n ⟹ m a x P r o d u c t = x n x , ( x 为 均 分 的 长 度 ) ⟹ f ( x ) = x n x = e n x l n x 的 极 大 值 为 目 标 值 ⟹ f ′ ( x ) = e n x l n x n x 2 ( 1 − l n x ) = 0 ; ⟹ x = e 是 f ( x ) ⟶ m a x ⟹ x 必 须 为 整 数 2 < e < 3 , 那 么 2 好 还 是 3 好 呢 ? ⟹ f ( 2 ) f ( 3 ) = e n l n 2 2 e n l n 3 3 = e l n 4 e l n 9 < 1 , 即 f ( 3 ) > f ( 2 ) ⟹ 这 说 明 我 们 需 要 尽 可 能 多 的 选 3 , 当 截 取 完 所 有 的 3 之 后 可 能 会 剩 下 1 或 者 2 两 种 可 能 , 如 果 是 2 则 直 接 截 取 即 可 , 因 为 2 > 1 ∗ 1 ; 但 是 如 果 剩 下 的 为 1 的 话 我 们 需 要 将 已 经 拆 分 的 3 结 合 1 变 成 2 、 2 , 原 因 为 2 ∗ 2 > 3 ∗ 1 \begin{aligned} &(\frac{a_1+a_2 +\cdots+a_n}{n})^n \geq a_1a_2\cdots a_n \\ \Longrightarrow & \ maxProduct = x^\frac{n}{x},(x \ 为均分的长度)\\ \Longrightarrow &\ f(x) = x^{\frac{n}{x}} = e^{\frac n x lnx}\ 的极大值为目标值 \\ \Longrightarrow &\ f'(x) = e^{\frac n x lnx} \frac{n}{x^2}(1 - lnx) = 0; \\ \Longrightarrow &\ x = e \ 是f(x) \longrightarrow max\\ \Longrightarrow &\ x\ 必须为整数 2< e < 3, 那么\ 2\ 好还是\ 3 \ 好呢?\\ \Longrightarrow &\ \frac{f(2)}{f(3)} = \frac{e^{nln2^2}}{e^{nln3^3}} = \frac{e^{ln4}}{e^{ln9}} < 1,即f(3) > f(2)\\ \Longrightarrow &\ 这说明我们需要尽可能多的选3,当截取完所有的3之后可能\\&\ 会剩下\ 1 或者\ 2\ 两种可能,如果是\ 2 则直接截取即可,因为\\ &\ 2 > 1 * 1; 但是如果剩下的为 1 的话我们需要将已经拆分的3\\ &结合1变成\ 2、2,原因为\ 2*2 > 3 * 1 \end{aligned} ⟹⟹⟹⟹⟹⟹⟹(na1+a2+⋯+an)n≥a1a2⋯an maxProduct=xxn,(x 为均分的长度) f(x)=xxn=exnlnx 的极大值为目标值 f′(x)=exnlnxx2n(1−lnx)=0; x=e 是f(x)⟶max x 必须为整数2<e<3,那么 2 好还是 3 好呢? f(3)f(2)=enln33enln22=eln9eln4<1,即f(3)>f(2) 这说明我们需要尽可能多的选3,当截取完所有的3之后可能 会剩下 1或者 2 两种可能,如果是 2则直接截取即可,因为 2>1∗1;但是如果剩下的为1的话我们需要将已经拆分的3结合1变成 2、2,原因为 2∗2>3∗1 - 经过上述分析我们发现我们的代码似乎可以优化,我们只需要全部取3即可,对于剩余的部分如果等于2则直接取2,如果为1则将1结合最后一个3变为2、2,共计三步操作。
优化后的代码
class Solution {
public:
int cuttingRope(int n) {
if(n == 2)
return 1;
if(n == 3)
return 2;
int maxProduct = 1;
int count = n / 3;
while(count > 0){
maxProduct *= 3;
--count;
}
if(n %3 == 2)
maxProduct *= 2;
else if(n % 3 == 1)
maxProduct = (maxProduct/3*4);
return maxProduct;
}
};
执行结果
题目来源 Leetcode, 感谢🙇,如果内容对您有帮助,欢迎点赞。