剑指Offer-JZ67剪绳子
Posted codejess
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指Offer-JZ67剪绳子相关的知识,希望对你有一定的参考价值。
- 题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
- 输入
n(绳子长度)
- 输出
答案
- 题目分析
约束:k[1]+...+k[m] = n
目标:MAX(πk[m])
- 初步思路
逐步确定绳子的每一段长度,暴力穷举递归得出答案。
// 确定第一段与其他段长度的乘积 public int fun(int n) { int con = 0; for (int i = n-1; i>=1; i--) { for (int j=n-i; j>=1; j--) { int item = func(n, i, j); con = Math.max(con, item); } } return con; } // 确定后续绳子长度 public int func(int n, int k, int max) { int con = 0; if (n - k - max < 2) { con = k * max; } else { for (int i = max; max>=1; max--) { if (i + max + k > n) continue; int item = k * func(n - k, max, i); con = Math.max(con, item); } } return con; }
光暴力就想了两个小时,果然菜是原罪,学习学习优化思想。
- 贪心算法
在对问题进行求解时,在每一步选择中都采取最好或者最优(即最有利)的选择,从而希望能够导致结果是最好或者最优的算法。
贪婪算法并没有固定的算法解决框架,算法的关键是贪婪策略的选择,根据不同的问题选择不同的策略。
必须注意的是策略的选择必须具备无后效性,即某个状态的选择不会影响到之前的状态,只与当前状态有关,所以对采用的贪婪的策略一定要仔细分析其是否满足无后效性。
思路:把绳长target剪成i段的最大值为:Math.pow(n, i - c) * Math.pow(n + 1, c),如:target=8 i=3时,ans=2^1*3^2然后在剪成2段、3段...x段中取最大值即可。
public int cutRope(int target) { int result = 0; for (int i = 2; i <= target; i++) { int n = target / i, c = target % i; int ans = (int) (Math.pow(n, i - c) * Math.pow(n + 1, c)); if (ans > result) { result = ans; } } return result; }
- 动态规划
①求一个问题的最优解;
②整体的问题的最优解是依赖于各个子问题的最优解;
③小问题之间还有相互重叠的更小的子问题;
④从上往下分析问题,从下往上求解问题;
思路:整体可由局部和局部的最优解相乘得到,如果把长度n绳子的最大乘积记为f(n),则有:f(n)=max(f(i)*f(n-1))
,因此不断由小推导至大,最终求出n的结果。因此设置一个数组用来存放对应的最大乘积数。
public int cutRope(int target) { //当长度大于3 f[n]才能得到绳子的最大乘积因为target>1,m>1 if(target==2) return 1; if(target==3) return 2; int [] f = new int[target+1]; f[0] = 0; f[1] = 1; f[2] = 2; f[3] = 3; for (int i = 4; i <f.length ; i++) { int max = 0; //计算f(n)*f(n-i) for (int j = 1; j <=i/2 ; j++) { int temp = f[j]*f[i-j]; max = Math.max(temp,max); } f[i] = max; } return f[target]; }
以上是关于剑指Offer-JZ67剪绳子的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode(剑指 Offer)- 14- I. 剪绳子