zoukankan      html  css  js  c++  java
  • 343.整数拆分

    题目

    给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

    示例 1:

    输入: 2
    输出: 1
    解释: 2 = 1 + 1, 1 × 1 = 1。

    示例 2:

    输入: 10
    输出: 36
    解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
    说明: 你可以假设 n 不小于 2 且不大于 58。

    思路

    这道题其实就是剑指offer上的剪绳子问题,有动态规划和贪心算法两种解法。

    动态规划

    dp[i]表示正整数i的最大乘积,则dp[i]=max{dp[i-1]*1, (i-1)*1, dp[i-2]*2, (i-2)*2, ... , dp[i-(i-1)]*(i-1), (i-(i-1))*(i-1)};
    之所以还要进行dp[i-j]*j和(i-j)*j的比较是因为可能i只进行一次划分,得到i-j不继续划分了

       public int integerBreak(int n) {
            int[] dp=new int[n+1];
            //1不能被划分
            dp[1]=1;
            for(int i=2;i<=n;i++)
                for(int j=1;j<i;++j)
                    dp[i]=Math.max(Math.max(dp[i-j]*j,j*(i-j)),dp[i]);
            return dp[n];
        }
    

    其实由下面贪心算法部分的分析可知,当n>=4时,划分得到结果都是大于等于不划分的结果的,那么此时就没有必要进行dp[i-j]*j和(i-j)*j的比较了,于是可以有下面的写法。
    注意这里的dp[i]并不是子问题的结果,因为题目中要求了必须拆分为至少两个正整数的和,这里的dp[i]并没有保证一定会划分,例如dp[2]=2而不是dp[2]=1*1=1)。因为n<4时,dp[i]都是没有经过划分的结果,所以n=2,n=3时需要单独返回。

      public int integerBreak(int n) {
            if(n==2) return 1;
            if(n==3) return 2;
            int[] dp=new int[n+1];
            //i<4时,dp[i]是没有经过划分的结果
            dp[2]=2;
            dp[3]=3;
            //i>=4时,dp[i]都是划分得到的结果
            for(int i=4;i<=n;++i){
                for(int j=2;j<i;++j){
                    dp[i]=Math.max(dp[i],dp[j]*(i-j));
                }
            }
            return dp[n];
      }
    

    贪心算法

    2*(n-2)>=n,解得n>=4。也就是说大于等于4的正整数都可以继续划分,故划分出来的正整数不能大于3。又显然有1*(n-1)<n,故划分出来的整数要么是2,要么是3

    那么是优先划分出来3,还是划分出来2呢?

    3*(n-3)>=2*(n-2),解得n>=5。即n>=5时,优先划分出3

    总结如下:

    n>=5时,优先划分出3;
    n=4时,优先划分出2(其实可以直接返回结果4);
    n<=3时,不划分。但题目要求拆分为至少两个正整数的和,那么n<=3时的情况可以单独返回。

      public int integerBreak(int n) {
            if(n==2) return 1;
            if(n==3) return 2;
            if(n==4) return 4;
            //默认n>=5,这时优先划分出3
            int numOf3=n/3;
            //划分到只剩下4的时候应该停止划分出3,因为3*(n-3)>=2*(n-2)的前提条件是n>=5
            if(n-numOf3*3==1) numOf3--;
            int numOf2=(n-numOf3*3)/2;
            return (int)Math.pow(3,numOf3)*(int)Math.pow(2,numOf2);
      }
    

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/integer-break
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 相关阅读:
    Linux混杂设备驱动学习
    Linux字符设备驱动解析
    U-BOOT-Linux启动指令bootm分析
    项目-基于视频压缩的实时监控系统--tiny6410
    django分页linaro-django-pagination
    django FileFIeld和ImageField 上传路径改写
    ajaxFileUpload用法
    gzip压缩
    编写EL函数
    struts2上传下载
  • 原文地址:https://www.cnblogs.com/Frank-Hong/p/14595706.html
Copyright © 2011-2022 走看看