Leetcode面试题14- I. 剪绳子(时间、空间100%)

382 阅读2分钟

题目描述:

给你一根长度为 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

题解:

class Solution {

    int[] res = null;
    public int cuttingRope(int n) {
        res = new int[n+1];
        res[2] = 1;
        for(int k=2;k<=n;k++){
            run(k);
        }
        return res[n];
    }

    public void run(int i){
        int cmp = 1;
        for(int j=2;j<=i;j++){
            int med = Math.max(j,res[j]);
            cmp = Math.max(cmp, med*(i-j));
        }
        res[i] = cmp;
    }
}

思路详解

假设输入值为n,输出值为S(n),则

S(8) = (8-7) * S(7)

S(8) = (8-6) * S(6)

S(8) = (8-5) * S(5)

......

S(8) = (8-2) * S(2)

即n=8时,可能的情况有以上几种。

但是,在S(8) = (8-7) * S(7)中,S(7)意味着长度为7的那段绳子至少被剪断一次,这与题意不符因为显然存在S(8) = 1 * 7的情况。所以对之前的分析还有缺陷。

因为要求最大乘积,所以需要在S(7)和7之间取较大值,则将上述表达式进行修改

S(8) = (8-7) * max[S(7), 7]

S(8) = (8-6) * max[S(6), 6]

S(8) = (8-5) * max[S(5), 5]

......

S(8) = (8-2) * max[S(2), 2]

即S(8)=上述6种情况的最大值。

每计算出一个S(n),将这个值保存到数组中,方便在求后面值的时候调用。

空间复杂度:O(n)
求长度为n的绳子,需要空间为n+1(空间也可以为n,但是为了使数组序号与绳子长度对应起来,使用n+1的空间)的数组。

时间复杂度:O(n²)
计算S(n)需要先计算S(2),S(3),S(4),......S(n-1)