剑指 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((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;
	

四、总结

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

以上是关于剑指 Offer 14- I. 剪绳子(C++暴力+动态规划贪心解)的主要内容,如果未能解决你的问题,请参考以下文章

剑指Offer面试题14- I. 剪绳子

[LeetCode]剑指 Offer 14- I. 剪绳子

剑指OFFER----面试题14- I. 剪绳子

LeetCode(剑指 Offer)- 14- I. 剪绳子

LeetCode(剑指 Offer)- 14- I. 剪绳子

速看,双100%剑指 Offer 14- I. 剪绳子 I