1. 程式人生 > 實用技巧 >【LeetCode-數學】剪繩子

【LeetCode-數學】剪繩子

題目描述

給你一根長度為 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。

示例:

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

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

說明:

  • 2 <= n <= 58;
  • 該題是《劍指Offer》的第 14 題;

題目連結: https://leetcode-cn.com/problems/jian-sheng-zi-lcof/

思路

將長度為 n 的繩子分成 a 段:

\[n = n_1 + n_2+n_3+\dots+n_a \]

使得,每段長度的乘積最大:

\[max(n_1 \times n_2 \times n_3 \times \dots \times n_a) \]

因為

上面的不等式當 \(n_1=n_2=\dots=n_a\) 時等式成立,也就是說均分長度為 n 的繩子時,得到的乘積最大。均分多少段才能得到最大值呢?假設均分為 a 段,每段的長度為 x,也就是 \(n = ax\),那麼每一段的乘積為:

\[x^a = x^{\frac{n}{x}} = (x^{\frac{1}{x}})^n \]

因為 n 是確定的,所以最大化 \((x^{\frac{1}{x}})^n\),就等於最大化 $ x^{\frac{1}{x}} $,我們對 \(x^{\frac{1}{x}}\) 取對數得到 \(\frac{1}{x} \ln x\),最大化 \(x^{\frac{1}{x}}\) 就等於最大化 \(\frac{1}{x} \ln x\),我們對 \(\frac{1}{x} \ln x\) 求導可得:

\[\frac{1}{x^2} - \frac{1}{x^2} \ln x \\ = \frac{1- \ln x}{x^2} \]

令上式為 0,可以得到 \(1-\ln x=0\),所以 x = e = 2.7.....,由於每段的長度 x 必須為整數,所以 x 為 2 或者 3 比較好。因為 \(3^{\frac{1}{3}}>2^{\frac{1}{2}}\),所以每段的長度為 3 最好。

我們可以得出以下結論:

  • 最優長度:3。把繩子儘可能切為多個長度為 33 的片段,留下的最後一段繩子的長度可能為 0,1,2 三種情況。
  • 次優長度:2。若最後一段繩子長度為 2 ;則保留,不再拆為 1 + 1。
  • 最差長度:1。若最後一段繩子長度為 1 ;則應把一份 3 + 1 替換為 2 + 2,因為 2 x 2 > 3 x 1。

所以演算法如下:

  • 如果繩子的長度 n 小於等於 3,因為必須要對繩子進行切分,所以我們將繩子分為 n-1 和 1 兩部分,返回 n-1;
  • a = n/3,b = n%3,表示 n 能切分成 a 段長度為 3 的繩子,並且最後一段繩子的長度為 b;
  • 如果 b==0,表示 n 能被 3 整除,返回 \(3^a\)
  • 如果 b==1,說明最後一段的長度為 1,則要將 3 + 1 轉換為 2 + 2,所以返回 \(3^{a-1}*4\)
  • 如果 b==2,說明最後一段的長度為 2,則返回 \(3^a*2\)

程式碼如下:

class Solution {
public:
    int cuttingRope(int n) {
        if(n<=3) return n-1;

        int a = n / 3;
        int b = n % 3;
        if(b==0) return pow(3, a);
        if(b==1) return pow(3, a-1) * 4;
        if(b==2) return pow(3, a) * 2;

        return 0; // 不會執行到這一步
    }
};
  • 時間複雜度:O(1)
  • 空間複雜度:O(1)

參考

https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-by/