剑指offer67_剪绳子_题解

剪绳子

题目描述

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

输入描述:

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

返回值描述:

输出答案。

示例1

输入

8

返回值

18

分析

方案一:记忆化递归

每次将一段绳子剪成两段时,剩下的部分可以继续剪,也可以不剪

  1. \(i*cuttingRope(n-i)\) 表示继续剪
  2. \(i*(n-i)\)表示不继续剪

求乘积最大值即取比较剪与不剪二者的乘积最大值

代码

/*
1.时间复杂度:O(n^2)
2.空间复杂度:O(n)
*/
class Solution
{
public:
    int memo[60] = {0};
    int cutRope(int n)
    {
        if (n == 2)
            return 1;
        if (memo[n] != 0)
            return memo[n];
        int ret = -1;
        // 每次将一段绳子剪成两段时,剩下的部分可以继续剪,也可以不剪
        for (int i = 1; i < n; ++i)
            ret = max(ret, max(i * (n - i), i * cutRope(n - i)));
        memo[n] = ret;
        return ret;
    }
};

方案二:动态规划

\(dp[i]\) 表示将正整数 \(i\) 拆分成至少两个正整数的和之后,这些正整数的最大乘积。

  1. 初始状态:\(dp[2]=1\)

  2. 状态转移方程:

    \[dp[i] = max(dp[i], max(j*(i-j), j*dp[i-j])) \tag{1<=j<=i} \]

  3. 返回值:\(dp[n]\)

代码

/*
1.时间复杂度:O(n^2)
2.空间复杂度:O(n)
*/
class Solution
{
public:
    int cutRope(int n)
    {
        vector<int> dp(n + 1);
        for (int i = 2; i <= n; ++i)
        {
            int curMax = 0;
            for (int j = 1; j < i; ++j)
            {
                curMax = max(curMax, max(j * (i - j), j * dp[i - j]));
            }
            dp[i] = curMax;
        }
        return dp[n];
    }
};
posted @ 2021-03-05 23:04  RiverCold  阅读(84)  评论(0编辑  收藏  举报