[343].整數拆分

 


題目

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

示例 1:

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

示例 2:

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

 


函數原型

C的函數原型:

int integerBreak(int n){}

 


邊界判斷

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

那就不需要邊界判斷。
 


算法設計:遞歸

從後往前看,如分割 4

分割 4 就有 3 個備選答案,分割 4 的最大乘積是:

  • 分割 3 的最大乘積 * 1 (拆分下來的,計算乘積最大值) = 一個備選答案
  • 分割 2 的最大乘積 * 2 = 一個備選答案
  • 分割 1 的最大乘積 * 3 = 一個備選答案

分割 4 的最大乘積 = 選出一個最大的備選答案。

分割 1 的最大乘積 就是 1,那分割 2 和 分割 3 的最大乘積呢?

不斷拆分即可。

一般化:

inline int max(int x, int y, int z){
    return (x>y?x:y)>z?(x>y?x:y):z;
}

int integerBreak(int n){
    if( n == 1 )    
        return 1;
    
    int max_ans = 0;
    for(int i=1; i<=n-1; i++)
        max_ans = max(max_ans, i*(n-i), i*integerBreak(n-i));

    return max_ans;
}

遞歸的複雜度:

  • 時間複雜度:Θ(2n)\Theta(2^{n})
  • 空間複雜度:Θ(n)\Theta(n)
     

算法設計:遞歸+記憶化搜索

遞歸有重複計算子問題,爲啥,我們不創建一個容器來存儲這些值,避免重複計算呢?

inline int max(int x, int y, int z){
    return (x>y?x:y)>z?(x>y?x:y):z;
}

int memo[64];

int integerBreak(int n){
    if( n == 1 )    
        return 1;
    
    if( memo[n] )   // 已經計算過
        return memo[n];

    int max_ans = 0;
    for(int i=1; i<=n-1; i++)
        max_ans = max(max_ans, i*(n-i), i*integerBreak(n-i));

    memo[n] = max_ans;
    return max_ans;
}

遞歸+記憶化搜索複雜度:

  • 時間複雜度:Θ(n)\Theta(n)
  • 空間複雜度:Θ(n)\Theta(n)
     

算法設計:動態規劃

這個問題中,我們從後往前分析,發現有重疊子問題,我們就可以使用記憶化搜索。

而解決子問題,就可以解決原問題,動態規劃就是要解決這類問題的。

關於動態規劃,請猛擊:《動態規劃》。

inline int max(int x, int y, int z){
    return (x>y?x:y)>z?(x>y?x:y):z;
}

int memo[64];

int integerBreak(int n){
    memo[1] = 1;

    for( int i=2; i<=n; i++ )
        for( int j=1; j<=i-1; j++ )
            memo[i] = max(memo[i], j*(i-j), j*memo[i-j]);

    return memo[n];
}

動態規劃的複雜度:

  • 時間複雜度:Θ(n)\Theta(n)
  • 空間複雜度:Θ(n)\Theta(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章