1. 程式人生 > 實用技巧 >🌞343. 整數拆分

🌞343. 整數拆分

2020.7.30 LeetCode

題目描述

給定一個正整數 n,將其拆分為至少兩個正整數的和,並使這些整數的乘積最大化。 返回你可以獲得的最大乘積。

示例

輸入: 2
輸出: 1
解釋: 2 = 1 + 1, 1 × 1 = 1。

輸入: 10
輸出: 36
解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

說明: 你可以假設 n 不小於 2 且不大於 58。

題解

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

思路

方法一:動態規劃
對於的正整數 nn,當 n \ge 2n≥2 時,可以拆分成至少兩個正整數的和。令 kk 是拆分出的第一個正整數,則剩下的部分是 n-kn−k,n-kn−k 可以不繼續拆分,或者繼續拆分成至少兩個正整數的和。由於每個正整數對應的最大乘積取決於比它小的正整數對應的最大乘積,因此可以使用動態規劃求解。

建立陣列 \text{dp}dp,其中 \text{dp}[i]dp[i] 表示將正整數 ii 拆分成至少兩個正整數的和之後,這些正整數的最大乘積。特別地,00 不是正整數,11 是最小的正整數,00 和 11 都不能拆分,因此 \text{dp}[0]=\text{dp}[1]=0dp[0]=dp[1]=0。

當 i \ge 2i≥2 時,假設對正整數 ii 拆分出的第一個正整數是 jj(1 \le j < i1≤j<i),則有以下兩種方案:

將 ii 拆分成 jj 和 i-ji−j 的和,且 i-ji−j 不再拆分成多個正整數,此時的乘積是 j \times (i-j)j×(i−j);

將 ii 拆分成 jj 和 i-ji−j 的和,且 i-ji−j 繼續拆分成多個正整數,此時的乘積是 j \times \text{dp}[i-j]j×dp[i−j]。

因此,當 jj 固定時,有 \text{dp}[i]=\max(j \times (i-j), j \times \text{dp}[i-j])dp[i]=max(j×(i−j),j×dp[i−j])。由於 jj 的取值範圍是 11 到 i-1i−1,需要遍歷所有的 jj 得到 \text{dp}[i]dp[i] 的最大值,因此可以得到狀態轉移方程如下:

\text{dp}[i]=\mathop{\max}\limits_{1 \le j < i}\{\max(j \times (i-j), j \times \text{dp}[i-j])\}
dp[i]= 
1≤j<i
max
​	
 {max(j×(i−j),j×dp[i−j])}

最終得到 \text{dp}[n]dp[n] 的值即為將正整數 nn 拆分成至少兩個正整數的和之後,這些正整數的最大乘積。