当前位置: 首页 > 科技观察

动态规划:整数拆分,怎么拆分?

时间:2023-03-19 21:52:53 科技观察

整数拆分给定一个正整数n,将其拆分为至少两个正整数的和,并最大化这些整数的乘积。返回您可以获得的最大产品。示例1:输入:2输出:1解释:2=1+1,1×1=1。示例2:输入:10输出:36解释:10=3+3+4,3×3×4=36。解释:你可以假设n不小于2,不大于58。思考看到这道题,你会想把它拆分成两个,或者三个,或者四个……下面我们来看看如何使用dynamic规则来解决它。动态规划规则的五个部分分析如下:1.判断dp表(dp表)和下标dp[i]的含义:拆分数i,最大可得到的乘积为dp[我]。dp[i]的定义就是执行整个问题求解过程。如果你不明白下面是哪一步,那就想想dp[i]到底代表什么吧!2、确定递归公式,想一想dp[i]的最大乘积得到什么?其实j可以从1开始遍历,然后有两种方法可以得到dp[i]。一种是j*(i-j)的直接乘法。一种是j*dp[i-j],相当于分裂(i-j)。如果不理解这个拆分,可以回忆一下dp数组的定义。那么有同学问,j为什么不拆分呢?j是从1开始遍历的,而splitj实际上是在遍历j的过程中计算出来的。然后从1开始遍历j,比较(i-j)*j和dp[i-j]*j,取最大的。递归公式:dp[i]=max(dp[i],max((i-j)*j,dp[i-j]*j));3.应该很多同学对dp的初始化比较困惑,dp[0]dp[1]应该初始化多少?有的解法会给出dp[0]=1,dp[1]=1的初始化,但是解释的很牵强,主要是这样的初始化可以过题。从dp[i]的定义严格来说,dp[0]dp[1]不应该被初始化,也就是无意义的值。拆分0和拆分1的最大乘积是多少?这是无解的。这里我只初始化dp[2]=1,从dp[i]的定义来看,将数2拆分得到的最大乘积为1,这个没有异议!确定遍历顺序确定遍历顺序。我们先来看看递归。公式:dp[i]=max(dp[i],max((i-j)*j,dp[i-j]*j));dp[i]取决于dp[i-j]的状态,所以遍历i必须从前向后遍历,先dp[i-j]再dp[i]。在枚举j的时候,是从1开始的,i是从3开始的,所以dp[i-j]就是dp[2],可以通过我们初始化的值来计算。所以遍历顺序是:for(inti=3;i<=n;i++){for(intj=1;jdp(n+1);dp[2]=1;for(inti=3;i<=n;i++){for(intj=1;j4){result*=3;n-=3;}result*=n;returnresult;}};时间复杂度O(n)空间复杂度O(1)总结掌握这道题的动态规律的方法,就可以了,贪心解法真的很简单,但是需要数学证明,能自圆其说就好了.其实这道题的递归公式不好想,初始化的地方也很有讲究。我写这道题的时候,一开始写的代码是这样的:classSolution{public:intintegerBreak(intn){if(n<=3)return1*(n-1);vectordp(n+1,0);dp[1]=1;dp[2]=2;dp[3]=3;for(inti=4;i<=n;i++){for(intj=1;j