算法题丨剪绳子

题目描述

给你一根长度为n的绳子,请把绳子剪成m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

输入描述

输入一个数n,意义见题面。(2 <= n <= 60)

输出描述

输出答案。

性能要求

时间限制:1秒 空间限制:65536K

题目分析

直接看题目是没有头绪,因而我们只有先一一列举几个,来查看是否有规律可循。

绳子长度n最大乘积段数m公式
2121*1
3222*1
4422*2
5623*2
6923*3
71233*4
81833* 3*2
92733* 3* 3
103633* 3* 4
115443* 3* 3* 2
128143* 3* 3* 3

由上表我们可以推断出,当绳子长度超过4后,要使得分段后每段长度乘积最大,需要满足公式为 3*m + x = n (m > 1 并且 m < n, x 属于 {2,3,4})。
因此根据该公式,我们在分段时,每次在总长度中减去3,直到剩下的那段长度x属于{2,3,4}。现在使用代码进行实现。

java实现

使用循环来得到结果

public class Solution {
    public int cutRope(int target) {
        if(target == 2){
            return 1;
        }else if(target == 3){
            return 2;
        }else if(target == 4){
            return 4;
        }
        int result = 1;
        while(target > 4 ){
            result = result * 3;
            target = target - 3;
        }
        
        return result * target;
    }
}

使用递归实现

public class Solution {
    public int cutRope(int target) {
        if(target == 2){
            return 1;
        }else if(target == 3){
            return 2;
        }else if(target == 4){
            return 4;
        }
        
        return process(target);
    }
    
    private int process(int target){
        if(target <= 4){
            return target;
        }else {
            return 3*process(target - 3);
        }  
    }

}

使用上面两种方式,也是我能够想到的,它们都能达到性能要求,完成该题。但这不是最优算法。下面我贴出大佬们的解题思路。

优解

绳子长度n最大乘积段数m公式
2121*1
3222*1
4422*2
5623*2
6923*3
71233* 2*2
81833* 3* 2
92733* 3* 3
103633* 3* 2*2
115443* 3* 3* 2
128143* 3* 3* 3

由此推导出的公式为
当 n % 3 =1 时,最大乘积 = 3^k * 2 * 2,k = n / 3 -1;
当 n % 3 = 2时,最大乘积 = 3^k * 2, k = n / 3;

相应的java代码如下

public class Solution {
    public int cutRope(int target) {
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n % 3 == 1) {
            int k = n / 3 - 1;
            return (int)Math.pow(3, k) * 2 * 2;
        }
        if (n % 3 == 2) {
            int k = n / 3;
            return (int)Math.pow(3, k) * 2;
        }
        return (int)Math.pow(3, n / 3);
    }
}

总结

方式一和方式二的差距是很大的。方式一仅仅是模拟出了规律,而方式二已经将这规律抽象为数学模型,思维的高度上了整整一个层次。我还需要多培养这方面的能力。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值