【刷题记录】21. 剪绳子

130 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

题目来源:LeetCode>剪绳子

给你一根长度为 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. 大体思路:动态规划
  2. 当绳子长度为0或1时,结果为0
  3. 从2开始,用dp[i]表示绳子长度为i时的最大结果
  4. 每次截取j长度,若后面不再截取则结果为j * (i - j),若截取则结果为j * dp[i - j] 则状态转移方程为max(j * (i - j), j * dp[i - 1])

思路二:

  1. 大体思路:贪心算法
  2. 尽可能把绳子分成长度为3的小段,这样乘积最大
  3. 如果 n == 2,返回1,如果 n == 3,返回2,两个可以合并成n小于4的时候返回n - 1
  4. 如果 n == 4,返回4
  5. 如果 n > 4,分成尽可能多的长度为3的小段,每次循环长度n减去3,乘积res乘以3;最后返回时乘以小于等于4的最后一小段

三、AC 代码:

思路一:

class Solution {
    public int cuttingRope(int n) {
        int[] dp = new int[n + 1];
        for(int i = 2; i < n + 1; i ++)
        {
            int cur_max = 0;
            for(int j = 1; j < i; j ++)
            {
                cur_max = Math.max(cur_max, Math.max(j * (i - j), j * dp[i - j]));
            }
            dp[i] = cur_max;
        }
        return dp[n];
    } 
}

思路二:

    class Solution {
        public int cuttingRope(int n) {
            if (n < 4) {
                return n - 1;
            }
            int res = 1;
            while (n > 4) {
                res *= 3;
                n -= 3;
            }
            return res * n;
        }
    }