【剑指offer】面试题14 剪绳子

本文深入探讨了剪绳子问题的两种主要算法解决方案——动态规划和贪心算法。通过对比不同算法的实现方式,详细解释了如何从数学角度推导出最优解,以及在实际编程中如何应用这些理论。文章提供了三种具体的代码实现,帮助读者理解和掌握算法的核心思想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.考点

  • 考点1:动态规划:核心思想为“从上到下分析问题,从下往上解决问题”,另外的三个特性为:① 求一个问题的最优解(最大值/最小值);② 整体最优解 = 各个子问题的最优解相加; ③ 小问题之间有共同的各个子小问题;这些是动态规划的特性,在分析问题时可以从这些角度来考虑,当然核心思想不仅仅只用在这些问题,可以用在很多相关问题里。(比如推导出了递推类公式:f(n) = max(f(i)*f(n-i)),其中0<i<n,然后从下往上地对问题进行解决)
  • 考点2:贪心算法:说穿了就是不断地取局部最优解,无论是剪绳子还是背包问题之类的,在循环中不断地取当前最优的解,直到最后发现更好的解,或者达到了循环的限制完成,其根据不同的题目有不同的变化,还是要多看题。

2.代码

  • 三种写法,第一种是动态规划,核心是理解f(2)与f(3)在作为主问题和子问题时的取值区别;第二种是参照书上的贪心算法写法,代码较为简洁;第三种是常规思路的贪心算法,在循环中不断选择当前的最优解(剪3),直到最后剪完或者到达4和2这两种特殊情况。
#include <iostream>
using namespace std;

//剪绳子问题,采用动态规划分析:“从上往下的分析问题,从下往上的解决问题”
//分析:作为主问题时f(n) = max(f(i)*f(n-i)),作为子问题时:f(n) = max(f(i)*f(n-i),n),解决:f(1) = 0,f(2) = 1, f(3) = 2
int maxProductAfterCutting_solution1(int length)
{
	//当成主问题时,n = 2时,其最大只能为1*1,而当n = 3时,其最大也只能为2*1
	//但是当他们被当成子问题时f(2)max = 2, f(3)max = 3

	//以下为length <= 3,当成主问题的最优解
	if (length < 2)
		return 0;
	if (length == 2)
		return 1;
	if (length == 3)
		return 2;
	
	//以下为length >= 4时,当成子问题的最优解
	int* bestSubProblem = new int[length + 1];
	bestSubProblem[0] = 0;
	bestSubProblem[1] = 1;
	bestSubProblem[2] = 2;
	bestSubProblem[3] = 3;

	int max = 0;
	for (int i = 4; i <= length; i++)
	{
		max = 0;
		for (int j = 1; j <= i >> 1; j++)
		{
			int submax = bestSubProblem[j] * bestSubProblem[i - j];
			if (submax > max)
			{
				max = submax;
				bestSubProblem[i] = max;
			}
		}
	}
	max = bestSubProblem[length];
	//cout << "max:" << max << endl;
	delete[] bestSubProblem;
	return max;
}

int maxProductAfterCutting_solution2(int length)
{
	//以下为length <= 3,当成主问题的最优解
	if (length < 2)
		return 0;
	if (length == 2)
		return 1;
	if (length == 3)
		return 2;
	if (length == 4)
		return 4;

	//f(3) = 3是最大的单子问题存在,f(4)是最小的单主问题存在
	//贪心思想:当n>=5时,尽可能地去剪去长度为3的绳子,当n=4时,剪成长度为2的绳子
	//1.尽可能地将绳子减为3(由于参与剪3的都是大于5的,所以至少会有1个3被剪出来)
	int cut_three = length / 3;
	//2.判断最后被剪到的长度是不是1,如果是则使其回到4
	if (length - cut_three * 3 == 1)
		cut_three--;
	//3.将剩余的部分剪2(可能的情况有剩2和剩4)
	int cut_two = (length - 3 * cut_three) / 2;
	//4.计算最终最佳数字
	return pow(3, cut_three)*pow(2, cut_two);
}

int maxProductAfterCutting_solution3(int length)
{
	//以下为length <= 3,当成主问题的最优解
	if (length < 2)
		return 0;
	if (length == 2)
		return 1;
	if (length == 3)
		return 2;
	if (length == 4)
		return 4;

	int cut_three = 0;
	int cut_two = 0;
	while (length)
	{
		if (length != 4 && length != 2)
		{
			length -= 3;
			cut_three++;
		}
		else
		{
			cut_two = length / 2;
			break;
		}
	}
	return pow(3, cut_three)*pow(2, cut_two);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方寸间沧海桑田

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值