【Java】面试题14:剪绳子

题目:剪绳子

给你一根长度为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。

主要思路:
思路一:动态规划:f(n) = max(f(i)*f(n-i)), 其中 0<i<n,从1到n/2遍历i,求出最大的f(n) 。为了避免重复计算,选择从下到上的顺序计算。

思路二:贪婪算法:当n大于等于5时,尽可能剪长度为3的绳子,当剩下长度为4时,把绳子剪成2段长度为2的绳子。
证明:n≥5时,2(n-2)>n, 3(n-3)>n, 并且3(n-3)≥2(n-2)
n=4时, 2×2>3×1

本题采用动态规划或者贪婪算法可以实现。一开始没有思路时,可以从简单的情况开始想,试着算以下比较短的绳子是如何剪的。

当n=1时,最大乘积只能为0;

当n=2时,最大乘积只能为1;

当n=3时,最大乘积只能为2;

当n=4时,可以分为如下几种情况:1111,121,13,2*2,最大乘积为4;

往下推时,发现n≥4时,可以把问题变成几个小问题,即:如果把长度n绳子的最大乘积记为f(n),则有:f(n)=max(f(i)*f(n-1)),0<i<n。所以思路就很容易出来了:从下往上推,先算小的问题,再算大的问题,大的问题通过寻找小问题的最优组合得到。

其实这就是动态规划法,以下是动态规划法的几个特点:

1.求一个问题的最优解

2.整体问题的最优解依赖各子问题的最优解

3.小问题之间还有相互重叠的更小的子问题

4.为了避免小问题的重复求解,采用从上往下分析和从下往上求解的方法求解问题

贪婪算法依赖于数学证明,当绳子大于5时,尽量多地剪出长度为3的绳子是最优解。

关键点:动态规划,贪婪算法

时间复杂度:动态规划:O(n^2);贪婪算法:O(1)

package jianZhiOffer;
/*
 * 面试题14:剪绳子
 * 题目:给你一根长度为n的绳子,请把绳子剪成m段(整数),每段绳子的长度记为k[0],k[1],...,k[m].
 * 请问k[0]*k[1]*...*k[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为
 * 2,3,3的三段,此时得到的最大乘积是18
 */
public class Demo14 {

	//动态规划
	public static int maxProductAfterCutting_solution(int length) {
		if(length<2)
			return 0;
		if(length==2)
			return 1;
		if(length==3)
			return 2;
		
		int[] products = new int[length+1];
		//n=2时,因为必须要减一刀,只能剪成1和1,所以最大乘积是1
		//但是初始化products[2]的时候,是为了计算n>3的情况,因此如果
		//有长度为2的肯定至少剪了一刀,这时候长度为2的最大乘积是2.
		products[0] = 0;
		products[1] = 1;
		products[2] = 2;
		products[3] = 3;
		
		int max=0;
		for(int i=4;i<=length;i++) {
			for(int j=1;j<=i/2;j++) {
				int currentproduct = products[j]*products[i-j];
				if(max<currentproduct)
					max = currentproduct;
			}
			products[i] = max;
		}
		max = products[length];
		return max;
	}
	
	//贪婪算法
	public static int maxProductAfterCutting_solution2(int length) {
		if(length<2)
			return 0;
		if(length==2)
			return 1;
		if(length==3)
			return 2;
		
		//当n>5的时候,尽可能多地剪去长度为3的绳子段
		int timesOf3 = length/3;
		
		//当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子段
		//此时更好的方法是把绳子剪为长度为2的两段
		if(length-timesOf3*3==1)
			timesOf3 -= 1;
		int timesOf2 = (length - timesOf3*3)/2;
		
		return (int) ((Math.pow(3, timesOf3))*(Math.pow(2, timesOf2)));
	}
	public static void main(String[] args) {
		int length = 8;
		int expected = 18;
		int result = maxProductAfterCutting_solution(length);
		System.out.println(result);

	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值