• 剑指67.剪绳子


    题目描述

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

    思路

    应用动态规划求解问题的特点:

    • 题目是求一个问题的最优解(最大值或最小值);
    • 该问题能分解成若干个子问题(整体问题的最优解依赖各个子问题的最优解);
    • 子问题之间还有相互重叠的更小的子问题;
    • 从上往下分析问题,从下往上求解问题(把已经解决的子问题的最优解存储到数组里,并把子问题的最优解组合起来逐步解决大问题)
    • 每一步都可能面临若干个选择,只能把所有的可能都尝试一遍。

    贪婪算法和动态规划不一样。应用贪婪算法解决问题时,每一步都可以做出一个贪婪的选择,基于这个选择,确定能够得到最优解。

    思路1:动态规划。         (时间复杂度:O(n^2), 空间复杂度:O(n))

    (1)计算顺序自下而上,在求f(i)之前,对于每一个j(0<i<j)而言,f(j)都已经求解出来了。

    (2)求所有可能的f(j)*f(i-j),并比较得出它们的最大值。

    思路2:贪婪算法。        (时间复杂度:O(1),空间复杂度:O(1))

        按照如下的策略剪绳子,则得到的各段绳子的长度的乘积最大:

    • 当n>=5时,尽可能多地剪长度为3的绳子;
    • 当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子。

    也就是

    • 当n能被3整除时,乘积=3^(n/3);
    • 当n除3余1时,这时候发现多了一个1,于是拿出前面的一个3,然后把这个1和前面那个3分解为2*2,所以乘积为 3^(n/3 - 1) * 4;
    • 当n除3余2时,乘积为3^(n/3) * 2

    ☆☆解法1(动态规划)

    public class Solution {
        //动态转移的方程为:dp[n] = dp[n - i] * dp[i],枚举i即可(1~n/2)
        public int cutRope(int target) {
            int[] dp = new int[target + 1]; // 0 ~ target
            if (target == 2)
                return 1;
            if (target == 3)
                return 2;
            dp[1] = 1;
            dp[2] = 2;
            dp[3] = 3;
            for (int i = 4; i <= target; i++) {
                for (int j = 1; j <= i / 2; j++) {
                    dp[i] = Math.max(dp[i], dp[j]*dp[i-j]);
                }
            }
            return dp[target];
        }
    }

    Note: n<=3时,要分段。但是n>=4时,3就不要再分了,因为3分段要小于3,我们要记录最大的。

    ☆☆解法2(贪婪算法)

    public class Solution {
        public int cutRope(int target) {
            if (target == 2)
                return 1;
            if (target == 3)
                return 2;
            if (target % 3 == 0){
                return (int)Math.pow(3,target / 3); // 全3
            }else if (target % 3 == 1){
                return (int) Math.pow(3,target / 3 - 1) * 4;
            }else{ // target % 3 == 2
                return (int) Math.pow(3, target / 3) * 2;
            }
        }
    }
  • 相关阅读:
    Android——ListView学习笔记(一)
    记录笔记——关于request.getRequestDispatcher().forward(request, response)的跳转问题
    Python + openCV 实现图像垂直投影和水平投影
    2020年-第三周助教总结-第二组
    Python记录——字符串的常用方法
    2020年-第二周助教总结-第二组
    Android开发——三种活动跳转方式
    2020年-第一周助教总结-第二组
    Python —— 实例化ndarray对象
    海信聚好看矫恒浩:构建异地双活混合云,利用公共云应对流量突增
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/13673784.html
Copyright © 2020-2023  润新知