剑指 Offer 14- I. 剪绳子(C++暴力+动态规划贪心解)
Posted --believe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 14- I. 剪绳子(C++暴力+动态规划贪心解)相关的知识,希望对你有一定的参考价值。
一、题目
剑指 Offer 14- I. 剪绳子
题目描述
给你一根长度为 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。
示例1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
二、分析
方法1 暴力+动态规划
这道题剪绳子,我们用动态规划的思想去做。
- 假设动态规划 f(i)表示i长的绳子切割后最大长度 f ( i ) = m a x ( ( i − k ) k , f ( i − k ) k ) ) 其 中 k = [ 2 , i ) f(i)=max((i-k)k,f(i-k)k))其中k=[2,i) f(i)=max((i−k)k,f(i−k)k))其中k=[2,i),k表示第一段割下来的长度
- 依次从i长的绳子里面割j长的绳子.剩下的 ( i − j ) (i-j) (i−j)长绳子可以不再分割:最大乘积就为 ( i − j ) ∗ j (i - j) * j (i−j)∗j。
- 也可以再次分割,最大乘积就为: j ∗ d p [ i − j ] j * dp[i - j] j∗dp[i−j]。两者取最大。
- 而最外面的max是因为第一段可以割不同的 j j j(暴力思想),需要不断更新。
方法2 贪心算法
-
要考虑尽可能每一段都要分隔成3的长度。
-
将特殊情况绳长小于等于3情况的去除掉
-
将绳长大于4的情况,不断切割下3的绳子,可能最后剩下4,3,2,剩下的正好作为单独一段。
-
**注意:**这里为什么条件是大于4,而不是大于当于4。因为如果等于4,那么4就会在被分隔成3+1 ,这两段乘积3x1=3。我们知道4切割后最大的乘积应该是2x2=4。因此我们这里干脆将条件设为大于4,那么最后就可能剩下一段绳子长度为4。正好符合4切割后的最大乘积4。
三、代码
方法1 暴力+动态规划
/*
* 题目:剑指 Offer 14- I. 剪绳子
* 描述:给你一根长度为 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
* 实现:暴力+动态规划 f(i)表示i长的绳子切割后最大长度 f(i)=max((i-k)*k,f(i-k)*k)) 其中k=[2,i),表示第一段割下来的长度
1.依次从i长的绳子里面割j长的绳子.剩下的(i-j)长绳子可以不再分割:最大乘积(i - j) * j。
2.也可以再次分割:j * dp[i - j]。两者取最大。
3.而外面max是因为第一段可以割不同的j(暴力思想),需要不断更新。
* 复杂度:时间O(n^2): 循环次数 1+2+....+n-2=(n-1)*(n-2)/2
* 空间 O(n):线性辅助空间
*/
int cuttingRope(int n)
int* dp = new int[n + 1] 0 ;
dp[2] = 1;//初始值
for (int i = 3; i <= n; i++)
//依次从i长的绳子里面割j长的绳子.剩下的(i-j)长绳子可以不再分割:最大乘积(i - j) * j。
//也可以再次分割:j * dp[i - j]。两者取最大。
//而外面max是因为第一段可以割不同的j,需要不断更新。
for (int j = 2; j < i; j++)
dp[i] = max(dp[i], max((i - j) * j, j * dp[i - j]));
return dp[n];
方法2 贪心算法
/*
* 题目:剑指 Offer 14- I. 剪绳子
* 描述:给你一根长度为 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
* 实现:贪心算法。每一段都要分隔成3
* 复杂度:时间O(logn):大约执行x次,3^x=n,所以x=log3(n)
* 空间 O(1):常数辅助空间
*/
int cuttingRopeA(int n)
if (n <= 3) return n - 1;
int res = 1;
while (n > 4)
res = res * 3;
n = n - 3;
return res * n;
四、总结
这道题核心是想到用动态规划的思想来做。可能第二种贪心算法在有限时间内不容易证明出来,但是第一种动态规划思想还是比较常见,应该要会掌握。
以上是关于剑指 Offer 14- I. 剪绳子(C++暴力+动态规划贪心解)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode(剑指 Offer)- 14- I. 剪绳子