动态规划2 -------整数拆分
Posted AppleApple
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划2 -------整数拆分相关的知识,希望对你有一定的参考价值。
突然想起来,关于算法方面的描述大部分人是不看的,没有必要搞模板把排版搞得花里胡哨的,直接写就是完事了。
题目描述:
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。
题注:本题难点在于不知道会将一个数拆成几个数相加,如果只是两个数的话很好做,但是示例2已经说明不是两个数了,个人觉得这种题还是得往动态规划上去靠。目前为止,这就是我脑子里关于这道题理解的所有知识储备了, 看了题注之后就发现原来这道题是这么简单,这里做一下引用,结尾贴出来引用文章。
看完题解之后的分析:
鬼都知道这道题应该需要递归,那么如何层次把题目剥离出来,是非常关键的,
这道题抽象一下就是:
令:(图 1)
求:
(图 2)
当然这里ni是未知的,多少个数是不知道的,每个数的大小也是不知道的。昨天和胖子聊我对动态规划的感悟是,别管中间的过程变量,只要了解,过程中应该能得到的最优的值就行了,用动态规划的方法层层剥离才是我们需要掌握的正确方式。这样,我们剥第一层洋葱,我们可以把给定的n想象为两个数相乘,比如原来的n可以由5个数相加,并且这5个数相乘是可以得到最大的结果的,那么我们想让前四个数相乘,然后用最后一个数和前面的数相乘就行了吧,原理上是一样的,
-
我们将原问题抽象为 f(n) -
那么 f(n) 等价于 max(1 * fn(n - 1), 2 * f(n - 2), ..., (n - 1) * f(1))。
核心在于这个max,同时不能忘了,有时候fn(n-1) <n-1,所以max需要比较一个list就是 max({MAX, j*(i-j), j*fn(i-j)})
用数学公式表示就是:
(图 3)
子问题依旧可以转化为一个单独的问题去求解,这种嵌套式的递归结构时间复杂度为O(n^n),但是明显是可以使用引入辅助数组来让时间复杂度猛降的,这种数组在动态规划中经常用到,只不过我在学习的过程中总是习惯记他的形式,而忘记了数组设计本身存在的意义,数组是将递归转化为非递归的一种重要手段,因为递归的函数记忆性不高,使用数组来提高记忆力,最终就可以转化为求一个长度为n的数组,里面每一个序列对应的值都是序列值所能取得最大乘积的结果。仔细一看这个不是浩哥说的小青蛙变态爬楼梯版吗。爱了爱了。
递归方法引用python的了,下面的c++方法我自己撸。
class Solution:
def integerBreak(self, n: int) -> int:
if n == 2: return 1
res = 0
for i in range(1, n):
res = max(res, max(i * self.integerBreak(n - i),i * (n - i)))
return res
关于动态规划的问题,我想引用原作者的一句话,动态规划就是建表查表,
贴一下c++代码:
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n+1, 0);
int MAX;
dp[1] = 1;
for (int i = 2; i <= n ; ++i) {
MAX = 0;
for (int j = 1; j < i; ++j)
MAX = max({MAX, j*dp[i-j], j*(i-j)});
dp[i] = MAX;
}
return dp[n];
}
};
以上是关于动态规划2 -------整数拆分的主要内容,如果未能解决你的问题,请参考以下文章