剑指Offer14-I.剪绳子

题目链接:剪绳子

思路:

  1. 暴力(会超时)。假设输入为n,那么当某个位置的左边长度为i,右边长度为n-i时,可以枚举出四种情况:

    • 左边进行分段,右边进行分段。那么变成递归的行为,对左右段递归调用本方法。
    • 左边不进行分段,右边进行分段。同理,对右边递归调用。左边长度为本身。
    • 左边进行分段,右边不进行分段。同理,对左边递归调用。右边长度为本身。
    • 左边不进行分段,右边不进行分段。那么,左右长度都为本身,此时,该绳子只分了2段。
  2. 动态规划。设置一个数组dp[n],dp[i]表示以长度为i的最大分段乘积。状态转移方程为(dp[n] = max_{i=1,2,...,n-1}{dp[n-i]*i, (n-i)*i})。当长度为n-1时,知道dp[n-1],此时再增加1个长度,总长度变为n,那么进行分段时,右边长度为i,左边最大分段长度为dp[n-i],但左边不存在不分段的情况,因此要考虑(dp[n-i]*i)是否大于((n-i)*i)的情况。

代码:

//动态规划
class Solution {
    public int cuttingRope(int n) {
        int[] dp = new int[n+1];
        dp[0] = dp[1] = dp[2] = 1;
        for(int i=2; i<=n; i++){
            for(int j=1; j<=(i>>1); j++){
                int t = Math.max(j * (i - j), dp[i - j] * j);
                dp[i] = Math.max(dp[i], t);
            }
        }
        return dp[n];
    }
}
//暴力,n大于30时会超时
class Solution {
    public int cuttingRope(int n) {
        if(n == 1 || n == 2) return 1;
        if(n == 3) return 2;
        if(n == 4) return 2;
        int max = 0;
        for(int i=1; i<=(n>>1); i++){
            int left = cuttingRope(i);
            int right = cuttingRope(n-i);
            int t = Math.max(i * (n - i), left * right);
            t = Math.max(t, i * right);
            t = Math.max(t, left * (n - i));
            max = Math.max(max, t);
        }
        return max;
    }
}

执行用时:1 ms, 在所有 Java 提交中击败了43.38%的用户
内存消耗:35.4 MB, 在所有 Java 提交中击败了36.17%的用户

原文地址:https://www.cnblogs.com/liuyongyu/p/14199429.html