【LeetCode】面试题14-1. 剪绳子
题目:
思路:
1、如果m是确定值,则这m段越平均它们的乘积越大(数学直觉)。所以遍历所有的M(最小2段,最大n段),计算当前m下的最大值,然后对比得到所有M下的最大值。
2、不需要遍历所有的M,根据如下两条数学推论直接计算最大值
- 将绳子以相等的长度等分为多段,得到的乘积最大。
- 尽可能将绳子以长度3等分为多段时,乘积最大。
- 当n<=3时,按照规则不切分。但题目要求必须切分(m>1),所以返回n-1
- 当n>3时,求n除以3的整数部分a和余数b(n=3a+b),则
-
b=0,直接返回3^a
-
b=1,乘以1和没乘一样,所以将一个3拿出来和1一起分成两个2,返回4x3^(a-1)
-
b=2,返回2x3^a
-
3、动态规划,对长度为n的绳子进行切割,可以划分成子问题(最优子结构、无后向性、重叠子问题)。递归函数为F(n)=max(i x (n-i), i x F(n-i)), i=1, 2, ..., n-2
代码:
Python
import math
class Solution(object):
def cuttingRope(self, n):
"""
:type n: int
:rtype: int
"""
# # 暴力搜索M切分段数,对每次切分尽量平分
# res = 0
# for i in range(2, n+1):
# a = n // i
# b = n % i
# tmp = math.pow(a, i - b) * math.pow(a + 1, b)
# if tmp > res:
# res = int(tmp)
# return res
# # 尽量平分,使得每段长度为3
# if n <= 3:
# return n - 1
# a = n // 3
# b = n % 3
# if b == 0:
# return int(math.pow(3, a))
# if b == 1:
# return 4 * int(math.pow(3, a - 1))
# if b == 2:
# return 2 * int(math.pow(3, a))
# 动态规划
dp = [0 for _ in range(n + 1)]
dp[1] = 1
dp[2] = 1
for i in range(3, n + 1): # 当前绳子长度为i
for j in range(1, i): # 第一刀切分长度
dp[i] = max(dp[i], j * (i - j), j * dp[i - j])
return dp[n]