剑指offer- 剪绳子

汇总:剑指offer算法合集

题目

给你一根长度为 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

提示:

2 <= n <= 58

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof

解题思路

  • 这道题首先想到的就是动态规划,用dp[i]表示长度为i的绳子剪成m端后长度的最大乘积,如果当前已经减了一段长度为j,那么剩下那段长度如果不再剪的话总乘积就是j*(i - j),如果继续剪的话,那总乘积就是j*dp[i-j],而长度i的最大乘积就是取这两种情况的最大值,因此转移方程为:
    d p [ i ] = m a x ( j ∗ ( i − j ) , j ∗ d p [ i − j ] ) dp[i] = max( j * (i-j), j * dp[i - j]) dp[i]=max(j(ij),jdp[ij])

  • 但今天我们用另一种思路解答本题,如果对这些长度多次进行尝试,我们可以发现,不管剪多少次,当剪出来的长度接近总长度的平均分配(除全剪为1外),值就越大,比如对于10来说,如果剪3次,均衡点剪成 3*3*4 = 36,会比不均衡剪成2*3*5=302*4*4=32这些要大,因此对于每一次剪数,我们都计算它平均分配情况下的乘积,就是这种剪数的最大乘积,然后循环比较每一种剪数的最大乘积,得出最终的最大乘积

  • 如果推导一番,其实会发现尽可能均分为3是最优的,但这里针对面试,也就没必要追究这些了,能用上面的方法解出来已经不错了

复杂度分析

循环尝试n-2中剪法,时间复杂度为O(n),然后在每种剪法中根据剪的段数循环计算乘积,时间复杂度为O(n),因此总的时间复杂度为O(n²),只用到了常数级变量,空间复杂度为O(1)

代码实现

class Solution {
    public int cuttingRope(int n) {
        //当n=2时,只有一种剪法,直接返回其乘积即可
        if (n == 2) return 1;
        //max是最终最大乘积
        //part是当前剪的每一段的平均长度
        //pow是当前剪数下的最大乘积
        //remain是无法平均分配剩余的长度
        //例如10平均分2段,则part = 10/2 = 5,remain = 0
        //10平均分3段,则part = 10/3 = 3,remain = 1
        int max = 0, part, pow, remain;
        //i代表当前剪的段数目,剪1次就会分2段,因此从2开始
        //长度为n的绳子最多可以剪n-1次变成n段均分长度为1的段
        //但由于均分全为1的长度乘积只有1,所以可以排除
        //因此最多剪n-2次分成n-1段即可
        for (int i = 2; i < n; i++) {
            //乘积初始值为1,如果是0的话相乘就都是0了
            pow = 1;
            //长度均分,也就是长度除以剪数
            part = n / i;
            //长度均分后剩余的长度
            remain = n % i;
            //把这些均分的长度相乘
            for (int j = 0; j < i; j++) {
                //如果有剩余的长度
                if (remain > 0) {
                    //就把它平均分配给均分后的那些段,每个分配1
                    pow *= part + 1;
                    remain--;
                } else {
                    //由于剩余的长度必定没有均分的长度长
                    //因此必定在后面某一次循环后剩余长度分配完了
                    //就乘以均分的长度即可
                    pow *= part;
                }
            }
            //比较每种剪数的最大乘积,取最终的最大乘积
            max = Math.max(max, pow);
        }
        return max;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Nbin_Newby

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

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

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

打赏作者

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

抵扣说明:

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

余额充值