算法:剪绳子
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、问题描述
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。
请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
二、常规解法
解题思路:
这道题是有规律的,一个数可以有很多种不同的组成方法,但是恰恰是数字最接近的时候,乘积最大。
例如7:拆成两个数的组合有1+6? 2+5? 3+4? ,对应的乘积分别是6? 10? 12。拆成三个数的组合且不包含1的有 3+2+2,对应的乘积是12。最大的两种组合分别是3+4和3+2+2,这两种实际上没区别,因为4=2+2。
例如8:拆成两个数的组合有1+7? 2+6? 3+5? 4+4? ,对应的乘积分别是7? 12? 15? 16。拆成三个数的组合且不包含1的有 2+2+4? 3+3+2,对应的乘积分别是16? 18。最大的组合是3+3+2。
例如9:拆成两个数的组合有1+8? 2+7? 3+6? 4+5? ,对应的乘积分别是8? 14? 18? 20。拆成三个数的组合且不包含1的有 2+2+5? 2+3+4? 3+3+3,对应的乘积分别是20? 24? 27。最大的组合是3+3+3。拆成4个数的组合有2+2+2+3,对应的乘积是24。
综上来看,我们总结一下规律:
最大的组合,对应到每个子元素,发现他们之间的差值都是小于等于1,那怎么将一个值拆成差值最小的组合呢?我们用均等拆分来看看。
例如7:先拆出来一个元素1,剩余是6;如果我要再增加一个元素,并且增加完之后,所有元素值保持一致,那就是2个元素值为2的元素,剩余3;如果我按照上边的思路再分的时候,发现我前边两个元素都需要再加1,第三个元素要加3,一共需要4,剩余不满足,那么这种方式分配就只能到这里了。那么剩下的3怎么分配呢?我们来看看剩下的3够不够再分配一个元素2,发现可以,那么我们再分配出来一个2,当前组合为:2+2+2,剩余1,剩余1肯定不能单独再分配一个元素,否则跟没分配没什么区别,那么就将其加到第一个元素上,最终组合为:3+2+2
例如8:快速的看一下分配的过程
第一次分配? ?当前1 剩余7
第二次分配? ?当前2+2?剩余4
第三次分配? ?当前2+2+2?剩余2
第四次分配? ?当前3+3+2?剩余0
例如9:快速的看一下分配的过程
第一次分配? ?当前1 剩余8
第二次分配? ?当前2+2?剩余5
第三次分配? ?当前3+3+3 剩余0
代码示例:?
public void test() {
int n = 11;
// 记录拆分后的每个元素
int[] array = new int[n];
// 记录大于0的元素个数
int size = 0;
// 剩余数字
int left = n;
// 每个元素的值
int value = 0;
// 如果剩余的数字足够前边size个元素每个再+1, 并且下一个元素分配value+1的值, 那么继续
while(left >= (size + 1) + (value + 1)) {
// 元素位置向后移动
size++;
// 每个元素的值+1
value++;
// 对前size个元素重置赋值, 赋值为最新的value
for (int i = 0; i < size; i++) {
array[i] = value;
}
// 计算剩余的数字, 总数字减掉前size个元素的和
left = n - size * value;
}
// 如果剩余数字不够再分配一轮, 且还有剩余, 进下边的分支
if (left > 0) {
// 如果剩下的数字够分配一个新的元素, 元素的值与已分配的一致, (特殊场景已分配的元素值不为2+剩余数字不为2), 优先分配一个元素
if (left > value || (left == value && value != 2)) {
array[size] = value;
left = left - value;
}
}
// 剩余数字不为0, 将其平摊到已分配的数字上, 每个数字+1, 直至分配完剩余数字
if (left > 0) {
for (int i = 0; i < left; i++) {
array[i] = array[i] + 1;
}
}
Long total = 1L;
for (int i : array) {
if (i == 0) {
break;
}
// 输出大于0的元素
System.out.println(i);
// 计算乘积
total = total * i;
}
System.out.println("乘积总和:" + total);
}
总结
详细注释已添加,快来练习吧,简单到有手就行!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!