Skip to content

14. 剪绳子

来源

https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/

题目

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n 都是整数,n>1 并且 m>1),每段绳子的长度记为 k[0],k[1]...k[m] 。请问 k[0]*k[1]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是 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 小于 4 时,由于必须要切一刀,所以 F(2) = 1,F(3) = 2。结果反而没有不切大。
n 大于等于 4 时,2、3 就不需要再切 F(2) = 2,F(3) = 3。
设在 i 处切一刀,F(n) = F(i) × F(n-i),得到公式:
F(n) = Max (F(2) × F(n-2) ... F(n/2) × F(n/2))。
用一个数组 cache 存储每个 n 对应的 F(n), 可以减少重复的计算。

解题

js
/**
 * @param {number} n
 * @return {number}
 */
var cuttingRope = function (n) {
  if (n === 2) return 1;
  if (n === 3) return 2;
  const cache = [0, 1, 2, 3];
  for (let i = 4; i <= n; i++) {
    let max = 0;
    for (let j = 2; j <= i / 2; j++) {
      let res = cache[j] * cache[i - j];
      if (max < res) max = res;
    }
    cache[i] = max;
  }
  return cache[n];
};

思路 2

贪婪算法

找规律

n最优方案
21×1
31×2
42×2
52×3
63×3
73×4
83×3×2
93×3×3
103×3×4

除以 3 取余:
余 0,3 ^ n;
余 1,3 ^ (n-1) × 4;
余 2,3 ^ n × 2。

解题

js
/**
 * @param {number} n
 * @return {number}
 */
var cuttingRope = function (n) {
  if (n === 2) return 1;
  if (n === 3) return 2;
  const m = (n / 3) >> 0;
  if (n % 3 === 1) return 3 ** (m - 1) * 4;
  if (n % 3 === 2) return 3 ** m * 2;
  return 3 ** m;
};

题目 2

在原题目上加上条件,答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

解题

js
/**
 * @param {number} n
 * @return {number}
 */
var cuttingRope = function (n) {
  if (n === 2) return 1;
  if (n === 3) return 2;
  let m = (n / 3) >> 0;
  function pow3(n) {
    let x = 1;
    while (n > 0) {
      x = (x * 3) % 1000000007;
      n--;
    }
    return x;
  }
  if (n % 3 === 1) return (pow3(m - 1) * 4) % 1000000007;
  if (n % 3 === 2) return (pow3(m) * 2) % 1000000007;
  return pow3(m);
};

从零开始学算法
https://github.com/daqi/re0-algorithm/issues
欢迎 start & watch

Waiting For Your Next Big Idea