动态规划 力扣 343. 整数拆分

动态规划 力扣 343. 整数拆分

题目看这里 343. 整数拆分

动态规划

这道题目有个很巧妙的解法是利用数学规律,但是我先讨论这道题的常规解法:动态规划。

题目要求把一个正整数拆分为两个或两个以上的正整数的和,然后求这些拆分出来的正整数的乘积。因为每一个数都依赖它前面比它小的正整数的值,所以考虑用动态规划。
设dp[i]是构成数字 i 的正整数的乘积,那么dp[i]=max( max( i*(i-j), j*dp[i-j] ), dp[i]),因为这个递推公式在最内层循环,所以每一次取最大值的时候需要把dp[i]也考虑进。
因为0,1都不能拆分,所以初始化dp[0]和dp[1]都是0,因为在后面的循环中会计算到dp[j],所以我没有使用dp[j]*dp[i-j],

class Solution {
    public int integerBreak(int n) {
        if(n<=3)return n-1;
        int[] dp=new int[n+1];
        for(int i=2; i<=n; i++){
            for(int j=1; j<i; j++){
                dp[i]=Math.max(Math.max(j*(i-j), j*dp[i-j]), dp[i]);
            }
        }
        return dp[n];
    }
}

另一种动态规划在上面的动态规划基础上做了一些小改进,在内层循环里面判断的是j<=i-j,并且dp[i]=Math.max(dp[i], dp[j]*dp[i-j]),这是因为使用dp[i]=Math.max(dp[i], dp[j]*dp[i-j])来获得dp[i]的最大值,不需要遍历整个i范围内的j的值。

class Solution {
    public int integerBreak(int n) {
        if(n<=3)return n-1;
        int[] dp=new int[n+1];
        dp[1]=1;
        dp[2]=2;
        dp[3]=3;
        for(int i=4; i<=n; i++){
            for(int j=1; j<=i-j; j++){
                dp[i]=Math.max(dp[i],dp[j]*dp[i-j]);
            }
        }
        return dp[n];
    }
}

数学方法

数学方法首先要证明“把正整数n分成尽可能多的正整数x,这些正整数的乘积最大”,证明的结果是 当把n分成多个3的和,这些3的乘积最大。具体证明可以看力扣官方题解,这个解法比较冷门。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注