算法題丨剪繩子

題目描述

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

輸入描述

輸入一個數n,意義見題面。(2 <= n <= 60)

輸出描述

輸出答案。

性能要求

時間限制:1秒 空間限制:65536K

題目分析

直接看題目是沒有頭緒,因而我們只有先一一列舉幾個,來查看是否有規律可循。

繩子長度n 最大乘積 段數m 公式
2 1 2 1*1
3 2 2 2*1
4 4 2 2*2
5 6 2 3*2
6 9 2 3*3
7 12 3 3*4
8 18 3 3* 3*2
9 27 3 3* 3* 3
10 36 3 3* 3* 4
11 54 4 3* 3* 3* 2
12 81 4 3* 3* 3* 3

由上表我們可以推斷出,當繩子長度超過4後,要使得分段後每段長度乘積最大,需要滿足公式爲 3*m + x = n (m > 1 並且 m < n, x 屬於 {2,3,4})。
因此根據該公式,我們在分段時,每次在總長度中減去3,直到剩下的那段長度x屬於{2,3,4}。現在使用代碼進行實現。

java實現

使用循環來得到結果

public class Solution {
    public int cutRope(int target) {
        if(target == 2){
            return 1;
        }else if(target == 3){
            return 2;
        }else if(target == 4){
            return 4;
        }
        int result = 1;
        while(target > 4 ){
            result = result * 3;
            target = target - 3;
        }
        
        return result * target;
    }
}

使用遞歸實現

public class Solution {
    public int cutRope(int target) {
        if(target == 2){
            return 1;
        }else if(target == 3){
            return 2;
        }else if(target == 4){
            return 4;
        }
        
        return process(target);
    }
    
    private int process(int target){
        if(target <= 4){
            return target;
        }else {
            return 3*process(target - 3);
        }  
    }

}

使用上面兩種方式,也是我能夠想到的,它們都能達到性能要求,完成該題。但這不是最優算法。下面我貼出大佬們的解題思路。

優解

繩子長度n 最大乘積 段數m 公式
2 1 2 1*1
3 2 2 2*1
4 4 2 2*2
5 6 2 3*2
6 9 2 3*3
7 12 3 3* 2*2
8 18 3 3* 3* 2
9 27 3 3* 3* 3
10 36 3 3* 3* 2*2
11 54 4 3* 3* 3* 2
12 81 4 3* 3* 3* 3

由此推導出的公式爲
當 n % 3 =1 時,最大乘積 = 3^k * 2 * 2,k = n / 3 -1;
當 n % 3 = 2時,最大乘積 = 3^k * 2, k = n / 3;

相應的java代碼如下

public class Solution {
    public int cutRope(int target) {
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n % 3 == 1) {
            int k = n / 3 - 1;
            return (int)Math.pow(3, k) * 2 * 2;
        }
        if (n % 3 == 2) {
            int k = n / 3;
            return (int)Math.pow(3, k) * 2;
        }
        return (int)Math.pow(3, n / 3);
    }
}

總結

方式一和方式二的差距是很大的。方式一僅僅是模擬出了規律,而方式二已經將這規律抽象爲數學模型,思維的高度上了整整一個層次。我還需要多培養這方面的能力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章