[LeetCode](面試題14- I)剪繩子

題目

給你一根長度爲 n 的繩子,請把繩子剪成整數長度的 m 段(m、n都是整數,n>1並且m>1),每段繩子的長度記爲 k[0],k[1]...k[m-1] 。請問 k[0]*k[1]*...*k[m-1] 可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別爲2、3、3的三段,此時得到的最大乘積是18。

示例 1:

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

示例 2:

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

提示:

  • 2 <= n <= 58

解題思路

解法一:動態規劃

定義函數 f(n) 爲把長度爲 n 的繩子剪成若干段後各段長度乘積的最大值,由於題目要求至少要剪一刀,假設第一刀剪在長度爲 j 的位置(1<=j<=n/2, j爲整數),那麼繩子就分成了 j 與 n-j 的兩段,那麼 f(n) = max(f(j)*f(n-j)), 其中1<=j<=n/2, j爲整數)。
初始值:

當 n=1 時,沒法減,f(1) = 0;
當 n=2 時,只能剪成 1+1 的兩段,所以 f(2) = 1*1 =1;
當 n=3 時,可以剪成 1+2 的兩段,所以 f(3) = 1*2 = 2;
當 n=4 時,可以剪成 1+3 的兩段,或者 2+2 的兩段,由於 2*2 > 1*3,所以 f(4) = 2*2 = 4;

複雜度分析:
時間複雜度:O(n^2)。
空間複雜度:O(n)。

解法二:貪心算法

歸納起來一句話,就是當 n>=5 時,應儘可能地多剪長度爲 3 的繩子。當剩下的長度爲 4 時,把繩子剪成兩段長度爲 2 的繩子。
證明:
1)當 n>=5 時,3*(n-3) > n,2*(n-2) > n,也就是說,當剩下的繩子長度大於等於5時,就把它剪成長度爲 3 或者 2 的繩子段。又當 n>=5 時,3*(n-3) >= 2*(n-2) ,所以應儘可能多剪出長度爲 3 的繩子段來。
2)當 n=4 時,如果要剪一刀,可以剪成 1+3 的兩段,或者 2+2 的兩段,由於 4 = 22 > 13,所以其實沒必要剪,只是題目要求至少要剪一刀,那就剪成 2+2 的兩段好了,最大乘積爲 2*2 = 4;
3)其他 n<4 的情況,見解法一。

複雜度分析:
時間複雜度:O(1)。
空間複雜度:O(1)。

代碼

解法一:動態規劃

class Solution {
    public int cuttingRope(int n) {
        // 特殊情況
        if(n<2){
            return 0;
        }
        if(n==2){
            return 1;
        }
        if(n==3){
            return 2;
        }
        // 其他情況
        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/2; j++){
                dp[i] = Math.max(dp[i], dp[j]*dp[i-j]);
            }
        }
        return dp[n];
    }
}

解法二:貪心算法

class Solution {
    public int cuttingRope(int n) {
        // 特殊情況
        if(n<2){
            return 0;
        }
        if(n==2){
            return 1;
        }
        if(n==3){
            return 2;
        }
        // 其他情況
        // 儘可能地多剪成3
        int time3 = n/3;
        int nextLen = n - 3*time3;
        // 如果最後剩下的長度爲1,那麼從3那裏拿出1來湊成2*2,因爲 2*2>3*1
        if(nextLen == 1){
            time3--;
        }
        int time2 = (n-3*time3)/2;
        int res = (int)(Math.pow(3, time3) * Math.pow(2, time2));
        return res;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章