剑指 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((ik)k,f(ik)k))k=[2,i),k表示第一段割下来的长度
  • 依次从i长的绳子里面割j长的绳子.剩下的 ( i − j ) (i-j) (ij)长绳子可以不再分割:最大乘积就为 ( i − j ) ∗ j (i - j) * j (ij)j
  • 也可以再次分割,最大乘积就为: j ∗ d p [ i − j ] j * dp[i - j] jdp[ij]。两者取最大。
  • 而最外面的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;
	}

四、总结

这道题核心是想到用动态规划的思想来做。可能第二种贪心算法在有限时间内不容易证明出来,但是第一种动态规划思想还是比较常见,应该要会掌握。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值