题目描述:
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k [ 0 ] , k [ 1 ] , . . . , k [ m ] k[0],k[1],...,k[m] k[0],k[1],...,k[m]。请问 k [ 0 ] × k [ 1 ] × . . . × k [ m ] k[0] \times k[1] \times ... \times 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
贪心算法
对于长度为 n n n的绳子要是剪成 m m m段后,段长度的乘积最大。首先我们先来观察一下简单的情形:
- 当 n = 0 n = 0 n=0时,自然为0
- 当 n = 1 n=1 n=1时,无法分割,结果为 1
- 当 n = 2 n=2 n=2时,可以分成1 + 1,结果为 1
- 当 n = 3 n = 3 n=3时,可以分为1 + 2,结果为 2
- 当 n = 4 n=4 n=4时,可以分成 2 + 2,结果为4
- 当 n = 5 n = 5 n=5时,可以分成 2 + 3,结果为6
- …
而且依次往后列举不同输入时的情况,每个 n n n分割后都是2和3的组合。因此,为了使乘积最大,我们要尽可能的剪成长度为3的段,然后才是长度为2的段,而且剪完后的结果都是2和3。假设长度为2有 x x x,长度为3有 y y y,那么乘积就等于 2 x × 3 y 2^x \times 3^y 2x×3y。
class Solution:
def cuttingRope(self, n: int) -> int:
if n == 0: return 0
if n == 1 or n == 2: return 1
if n == 3: return 2
countOfThree = n // 3 # 长度为3最多能剪多少段
if n - countOfThree * 3 == 1: # 如果除去长度为3的长度为1,则需要少剪一次
countOfThree -= 1
countOfTwo = (n - countOfThree * 3) // 2 # 长度为2的有多少段
return pow(3, countOfThree) * pow(2, countOfTwo)
动态规划
按照从下而上的顺序计算,先得到f(2),f(3),再计算f(4),f(5), f ( n ) = m a x ( f ( i ) × f ( n − i ) ) , 0 < i < n f(n)=max(f(i) \times f(n-i)),0<i<n f(n)=max(f(i)×f(n−i)),0<i<n。
class Solution:
def cuttingRope(self, n: int) -> int:
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
for j in range(1, i):
tmp = max(j, dp[j]) * max(i - j, dp[i - j])
dp[i] = max(dp[i], tmp)
return dp[-1]