题目
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/integer-break
思路
给定正整数,将其拆分为至少两个正整数的和。这个问题能否用递归的方法来解呢,简要的分析可以得出答案是肯定的。
可能直接思考分割n比较抽象,我们先来思考一个小一点的数,比如先思考 4 4 4是如何拆分的。下面画出递归树中的第一次分割:
要分割4,可以分割成1+?(这里的?表示可能为一个值,也可能是多个值)、2+?和3+?
其中只有1是不可再分的数字。
对于分割4来说,递归树如上。从上可以看出,存在重复子问题。并且分割1可以作为我们递归的终止条件。
如果仔细分析的话,还可以看出,分割1+3和分割3+1是同样的问题。因此,这里我们只需要分割到n//2+1
即可。
下面画出分割n的示意图:
这样我们就简要的画出了分割n的递归树。下面我们先用递归的方法来解。
代码
递归
class Solution:
# 定义递归方法
def breakInteger(self,n):
if n == 1:
return 1
max_result = -1
for i in range(1, int(n//2) + 1): #从1分割到 n//2 + 1
max_result = max(i * (n - i), i * self.breakInteger(n - i), max_result)
return max_result
def integerBreak(self, n: int) -> int:
return self.breakInteger(n)
上面我们分析得知,可以通过从1分割到 n//2 + 1
来加速算法。
重点来看下这段代码:
max_result = max(i * (n - i), i * self.breakInteger(n - i), max_result)
max_result = -1
初始化为-1
。然后比较当前最大值、直接用i * (n-i)
(就是说不对n-i
进行分割)、i * breakInteger(n - i)
(对n-i
进行分割后的最大值)三者之间的最大值,覆盖到max_result
中。
最终返回最大值即可,下面看下提交结果。
果然递归的方式会超时。
但是我们不慌,因为我们会改写成记忆化搜索了(参阅LeetCode刷题之动态规划思想)。
记忆化搜索
dp = {}
class Solution:
def breakInteger(self,n):
if n == 1:
return 1
if n not in dp:
max_result = -1
for i in range(1, int(n//2) + 1):
max_result = max(i * (n - i), i * self.breakInteger(n - i), max_result)
dp[n] = max_result
return dp[n]
def integerBreak(self, n: int) -> int:
return self.breakInteger(n)
改写成记忆化搜索也很简单,保存对传入的从参数n
进行分割的结果即可。
动态规划
最后改写成动态规划的方式。
class Solution:
def integerBreak(self, n: int) -> int:
# 因为n不大于58,我们可以用一个列表来保存,dp[1]=1作为已知条件,值为-1表示未计算过
dp = [1] * 2 + [-1] * (n-1) #dp[0]=1 ,dp[1] = 1, dp[2]到dp[n] = -1
for i in range(2, n + 1): # i从2到n
# 依次计算出dp[i]
for j in range(1,int(i/2)+1): # j从1到 i/2 + 1
# 拆分为j 和 (i-j)
dp[i] = max(dp[i], j * (i - j), j * dp[i - j]) #因为i-j < i的,而dp[i]在之前已经计算过了
return dp[n]
这里用了两个循环,依次计算出2到n的分割最大值。
外层循环是2到n;内层循环用1到 i/2 + 1
去分割i
。
这个题目动态规划的解法还没有记忆化搜索快。
在Python2中运行时间还是不错的。
在做完全平方数这个问题,自己写的解法需要几秒钟,不知道哪里写错了,就去看官方解法的时候,看到了这样一句话。
在LeetCode中提交时间Python3不知道为啥运行的时间超过Python2。 因此我尝试用Python2提交了一下,果然如此。
哈,以后就用Python2来写了。