LeetCode 343. Integer Break 动态规划,状态转移方程

343. Integer Break

Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get.

For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4).

Note: You may assume that n is not less than 2 and not larger than 58.

题意

给定一个整数n,将它分割为至少两个正整数,求出分割元素之后最大乘积之和。

思路

逐步实现暴力解法递归——>记忆化优化——>动态规划
给定一个具体的数值4,树形结构,每个结点是一个子问题
这里写图片描述
从上边可以看出存在大量重复计算。使用记忆化优化代码,可大大加快速度。
这里写图片描述

注意

在分割的过程中,分割成两个数的积,可能比分割成很多数的积大。

  • 状态转移方程
  • n分割为i和n-i,那么f(n1) = i*(n-i)
  • 继续对n-i进行分割,f(n2) = i*f(n-i),在此过程中不断更新乘积的最大值
  • f(n) = max(v(i)*v(n-i),v(i)*f(n-i))

代码

  • 纯递归 时间复杂度O(2^n)
class Solution {
private:
    int max3(int a, int b, int c)
    {
        return max(a,max(b,c));
    }
    //将n进行分割(至少分割为两部分),可以获得的最大值
    int breakInteger( int n ){
        if(n==1)  //当n为的时候不可再分割
            return 1;
        int res =-1;
        for( int i = 1 ; i <= n-1 ; i ++ )
            //每次都能将n分割为i和n-i   i+(n-i)
            //这里有个陷阱breakInteger是一定要将n分割为两个元素, 但是,在进行分割之前需要计算,i和n-i乘积的值也是一种可能
            res = max3(res,i*(n-i),i*breakInteger(n-i));  //不继续分割的情况,和继续对n-i进行分割所获得的乘积,寻找一个最大值.
        return res;
    }
public:
    int integerBreak(int n) {

       return breakInteger(n);
    }
};

这里写图片描述

  • 记忆化优化
class Solution {
private:
    vector<int> memo;
    int max3(int a, int b, int c)
    {
        return max(a,max(b,c));
    }
    //将n进行分割(至少分割为两部分),可以获得的最大值
    int breakInteger( int n ){
        if(n==1)  //当n为的时候不可再分割
            return 1;
        int res =-1;
        if(memo[n] != -1)
        {
            //对于计算过的直接返回,去除冗余计算
            return memo[n];   
        }
        for( int i = 1 ; i <= n-1 ; i ++ )
        {

            //每次都能将n分割为i和n-i   i+(n-i)
            //这里有个陷阱breakInteger是一定要将n分割为两个元素, 但是,在进行分割之前需要计算,i和n-i乘积的值也是一种可能
            res = max3(res,i*(n-i),i*breakInteger(n-i));  //不继续分割的情况,和继续对n-i进行分割所获得的乘积,寻找一个最大值.
        }
        memo[n] = res;  //对未计算过的结果存储起来
        return res;
    }
public:
    int integerBreak(int n)
    {
       memo = vector<int>(n+1,-1);

       return breakInteger(n);
    }
};

这里写图片描述

  • 动态规划,自底向上。 时间复杂度:O(n)
  • 底部最小分割1值为1 memo[1] = 1
  • 从2开始分割为{1,1},记录memo[2]的值;之后分割3为{1,2},其中继续将2分割,其值为memo[2]直接取,记录memo[3]最优值。以此类推,由底部向上不断逼近n
class Solution {
private:
    vector<int> memo;
    int max3(int a, int b, int c)
    {
        return max(a,max(b,c));
    }

public:
    int integerBreak(int n)
    {
       memo = vector<int>(n+1,-1);
       //memo[i]表示将数字i分割(至少分割成两部分)后得到的最大乘积

       memo[1] = 1; //对最基本的问题自底向上,底的部分设置
       for (int i=2;i<=n;i++)
       {
           //求解memo[i]
           for(int j=1;j<=i-1;j++)  //每一次将i分割为j和i-j两部分,对于这两个部分查看我们可以分割的最大乘积
           {
               memo[i] = max3(memo[i],j*(i-j),j*memo[i-j]);  //将i-j继续分割的最大乘积就是memo[i-j],i-j一定小于i,所以memo[i-j]一定被计算出来了 
           }
       }

       return memo[n];

    }
};

这里写图片描述

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值