剑指 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
提示:

2 <= n <= 58

 

二、分析:

  

1.问题分析:
    遇到这种把一个整数一次一次分成若干整数,然后这些整数相乘或相加的最大值的问题时,可以先考虑动态规划。
    一个长度为n的绳子,第一次把它剪一段长度为j,剩下的长度为n-j,第二次又继续对n-j进行重复的操作,或者可以不剪.(这样的问题可以依次分解成若干个小问题,并且重复相同的步骤,可以考虑用动态规划)

2.确定dp数组及其下标含义:
    dp[i]:表示长度为i的绳子剪成若干段,这些段的最大乘积。

3.初始化:
    0和1不可以剪,所以dp[1]=dp[0]=0。

4.推导公式:
    dp[i] = max(j*(i-j),dp[i-j]),j*(i-j)表示长度为i的绳子,剪了j,剩下的就不剪了;dp[i-j]表示剪了j,剩下的继续剪。dp[i]要多次遍历才能找到,所以还要和前一次遍历得到的dp[i]比较看看谁大。

4.遍历:
    从长度为2开始遍历到n,找每一个长度下的最大乘积,因为最后要返回dp[n];dp[i]是要多次遍历寻找的,比如长度为4,第一次剪了1,剩下的不知道要剪1还是2还是3,才能保证最后的乘积最大。(具体看代码再回头分析)
class Solution {
public:
    int cuttingRope(int n) {
        vector<int> dp(n+1);
        dp[0]=dp[1]=0;
        for(int i=2;i<=n;i++){//找最大乘积要保证前一次也是最大乘积
            for(int j=1;j<i;j++){
                dp[i] = max(dp[i],max(j*(i-j),j*dp[i-j]));//要和前一次遍历的dp[i]比较大小
            }
        }
        return dp[n];
    }
};

三、复杂度分析

 1.时间复杂度:O(n^2)

  其中 n 是给定的正整数。对于从 2到 n 的每一个整数都要计算对应的 dp 值,计算一个整数对应的dp 值需要 O(n) 的时间复杂度,因此总时间复杂度是 O(n^2)。

 2.空间复杂度:O(n),其中 n 是给定的正整数。创建一个数组 dp,其长度为 n+1。

 

posted @ 2022-09-04 11:30  湘summer  阅读(17)  评论(0编辑  收藏  举报