14 剪绳子
题目
给你一根长度为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。
C++题解
方法一
动态规划
class Solution {
public:
int maxProductAfterCutting(int length)
{
if (length < 2)
return 0;
if (length == 2)
return 1;
if (length == 3)
return 2;
int * products = new int[length + 1];
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3;
int max = 0;
for (int i = 4; i <= length; ++i)
{
max = 0;
for (int j = 1; j <= i / 2; j++)
{
int product = products[j] * products[i - j];
if (max < product)
max = product;
products[i] = max;
}
}
max = products[length];
delete[] products;
return max;
}
};
方法二
贪婪算法:
当n大于等于5时,我们尽可能多的剪长度为3的绳子;当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子。 为什么选2,3为最小的子问题?因为2,3包含于各个问题中,如果再往下剪得化,乘积就会变小。 为什么选长度为3?因为当n≥5时,3(n−3)≥2(n−2)3(n−3)≥2(n−2)
效率分析:
动态规划:空间复杂O(n),时间复杂\(O({n^2})\)。
贪婪算法:空间时间均为O(1)。
class Solution {
public:
int maxProductAfterCutting(int n)
{
if (n <= 3)
return 1 * (n - 1);
int res = 1;
if (n % 3 == 1)
res = 4, n -= 4;
else if (n % 3 == 2)
res = 2, n -= 2;
while (n)
res *= 3, n -= 3;
return res;
}
};
python 题解
方法一
动态规划
class Solution:
def maxProductAfterCutting(self, n):
# 动态规划
if n<2:
return 0
if n==2:
return 1
if n==3:
return 2
products=[0]*(n+1)
products[0]=0
products[1]=1
products[2]=2
products[3]=3
for i in range(4,n+1):
max=0
for j in range(1,i//2+1):
product=products[j]*products[i-j]
if product>max:
max=product
products[i]=max
#print(products)
return products[n]
方法二
贪婪算法
class Solution:
def maxProductAfterCutting(self, n):
# 贪婪算法
if n < 2:
return 0
if n==2:
return 1
if n==3:
return 2
timesOf3 = n//3
if n - timesOf3*3 == 1:
timesOf3 -= 1
timesOf2 = (n - timesOf3 * 3)//2
return (3**timesOf3) * (2**timesOf2)