剑指Offer-JZ67剪绳子

  • 题目描述

  给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

  • 输入

  n(绳子长度)

  • 输出

  答案

  • 题目分析

  约束:k[1]+...+k[m] = n

  目标:MAX(πk[m])

  • 初步思路

  逐步确定绳子的每一段长度,暴力穷举递归得出答案。

// 确定第一段与其他段长度的乘积
public int fun(int n) {
        int con = 0;
        for (int i = n-1; i>=1; i--) {
            for (int j=n-i; j>=1; j--) {
                int item = func(n, i, j);
                con = Math.max(con, item);
            }

        }
        return con;
}

// 确定后续绳子长度
public int func(int n, int k, int max) {
        int con = 0;
        if (n - k - max < 2) {
            con = k * max;
        } else {
            for (int i = max; max>=1; max--) {
                if (i + max + k > n)
                    continue;
                int item = k * func(n - k, max, i);
                con = Math.max(con, item);
            }
        }
        return con;
}

  光暴力就想了两个小时,果然菜是原罪,学习学习优化思想。

  • 贪心算法

  在对问题进行求解时,在每一步选择中都采取最好或者最优(即最有利)的选择,从而希望能够导致结果是最好或者最优的算法。

  贪婪算法并没有固定的算法解决框架,算法的关键是贪婪策略的选择,根据不同的问题选择不同的策略。

  必须注意的是策略的选择必须具备无后效性,即某个状态的选择不会影响到之前的状态,只与当前状态有关,所以对采用的贪婪的策略一定要仔细分析其是否满足无后效性。

  思路:把绳长target剪成i段的最大值为:Math.pow(n, i - c) * Math.pow(n + 1, c),如:target=8 i=3时,ans=2^1*3^2然后在剪成2段、3段...x段中取最大值即可。

public int cutRope(int target) {

        int result = 0;
        for (int i = 2; i <= target; i++) {
            int n = target / i, c = target % i;
            int ans = (int) (Math.pow(n, i - c) * Math.pow(n + 1, c));
            if (ans > result) {
                result = ans;
            }
        }
        return result;
}
  • 动态规划

  ①求一个问题的最优解; 
  ②整体的问题的最优解是依赖于各个子问题的最优解; 
  ③小问题之间还有相互重叠的更小的子问题; 
  ④从上往下分析问题,从下往上求解问题;

  思路:整体可由局部和局部的最优解相乘得到,如果把长度n绳子的最大乘积记为f(n),则有:f(n)=max(f(i)*f(n-1)),因此不断由小推导至大,最终求出n的结果。因此设置一个数组用来存放对应的最大乘积数。

public int cutRope(int target) {
        //当长度大于3 f[n]才能得到绳子的最大乘积因为target>1,m>1
        if(target==2)
            return 1;
        if(target==3)
            return 2;
        int [] f = new int[target+1];
        f[0] = 0;
        f[1] = 1;
        f[2] = 2;
        f[3] = 3;
        for (int i = 4; i <f.length ; i++) {
            int max = 0;
            //计算f(n)*f(n-i)
            for (int j = 1; j <=i/2 ; j++) {
                int temp = f[j]*f[i-j];
                max = Math.max(temp,max);
            }
            f[i] = max;
        }
        return f[target];
}
 

猜你喜欢

转载自www.cnblogs.com/codejess/p/13169795.html