整数拆分

力扣题目链接(opens new window)

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

示例 1:

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

示例 2:

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

思路

题目的要求很明确了,就是把整数拆解,让拆分结果相乘,积尽可能大

一个数学结论是:一个整数,如果要拆分之后再相乘得到尽可能大的值,那么拆分时就要拆成尽可能相同的m个数

上述结论在示例2中可以体现

对 10 进行拆分有很多种可能,但乘积相对大的几种可能都集中在拆分之后的数尽可能相同的几种情况中,例如:

5*5
3*3*4

取其中最大的情况作为结果即可(3 * 3 * 4)

再来看一下拆分的过程

还是以 10 为例:

10--->2  8
_--->2 6
_--->2 4
...

10 可以拆成 2 和 8;

然后 8 又进一步拆成 2 和 6;

以此类推,我们发现这里出现了一种递推的关系:

10 依靠 2 和 8 的状态;

8 依靠 2 和 6 的状态;...

因此可以使用dp

五步走

1、确定dp数组含义

给我们的数是 i ,要对 i 进行拆分,所以

dp[i]: 对i进行拆分得到的最大乘积为dp[i]

2、确定递推公式

怎么拆?有两种渠道得到dp[i]:

  • 一个是j * (i - j) 直接相乘
  • 一个是j * dp[i - j],相当于是拆分(i - j)

j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。

假设现在需要拆分的数是 i ,并且需要拆成两个数

那就可以表示如下:

j*(i-j)//j和(i-j)分别是拆分后得到的数

j表示遍历从[1,i]得到的所有情况

如果要拆成两个数或者以上呢?那就要表示如下:

j*dp[i-j]//j和(i-j)分别还是拆分后得到的数

不同的是,我们要对 i-j 进行进一步拆分,得到三个或三个以上的数

需要注意的是:上述拆分方式中,j 是固定的,在拆分 i-j 的过程中就会包括拆分j的所有情况,因此不用再对 j 进行拆分

(联想一下背九九乘法表的场景,横着背和竖着背最后都能得到所有情况)

如果要写成dp[j]*dp[i-j]就有点问题了

​ 第一,这么写表示 i 一定要继续拆分,这样可能就错过最大乘积了,相当于默认将一个数强制拆成4份以及4份以上了;(例如本来3 * 3 * 4最大了,拆i就拆成1 * 2 * 3 * 4,就不一定是最大了)

​ 第二,上述写法在初始化时不符合dp数组的含义;

总结一下

j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * jdp[i - j] * j 取最大的。

递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

(为什么还要加dp[i],后面在代码里解释)

3、确定初始化方法

首先,dp[0]和dp[1]其实是没有意义的,0、1拆不了

然后dp[2]是有意义的,为1,所以:

dp[0] = 0//0*0不影响
dp[1] = 0
dp[2] = 1

4、确定遍历顺序

先看递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历,先有dp[i - j]再有dp[i]。

所以遍历方式如下:

for(int i = 3; i <= n; ++i){
for(int j = 1; j < i - i; ++j){//从0开始没有意义
dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j)));
}
}

递推公式中取最大值时加入dp[i]的原因是,在第二层循环中,我们也要找到最大的dp[i],因为题意就是获取乘积最大的拆分结果(也就是dp[i])嘛

代码

本题代码很简单,就是分析过程比较难(纯数学题)

class Solution {
public:
int integerBreak(int n) {
//定义dp数组
vector<int> dp(n + 1);
//初始化dp数组
dp[0] = 0;
dp[1] = 0;
dp[2] = 1;
//遍历
for(int i = 3; i <= n; ++i){
for(int j = 1; j < i; ++j){//注意这里的循环条件,遍历范围是i
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]));
}
}
return dp[n];//注意返回值是dp[n],不用减1
}
};

需要注意循环的条件和返回值

【LeetCode动态规划#03】整数拆分(数学题)的更多相关文章

  1. [LeetCode] Integer Break 整数拆分

    Given a positive integer n, break it into the sum of at least two positive integers and maximize the ...

  2. LeetCode 343.整数拆分 - JavaScript

    题目描述:给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 题目分析 题目中"n 至少可以拆分为两个正整数的和",这个条件说 ...

  3. Java实现 LeetCode 343 整数拆分(动态规划入门经典)

    343. 整数拆分 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 示例 1: 输入: 2 输出: 1 解释: 2 = 1 + 1, 1 × ...

  4. LeetCode 343. 整数拆分(Integer Break) 25

    343. 整数拆分 343. Integer Break 题目描述 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 每日一算法2019/5/2 ...

  5. HDU 4651 Partition(整数拆分)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4651 题意:给出n.求其整数拆分的方案数. i64 f[N]; void init(){    f[0 ...

  6. LightOJ 1336 Sigma Function(数论 整数拆分推论)

    --->题意:给一个函数的定义,F(n)代表n的所有约数之和,并且给出了整数拆分公式以及F(n)的计算方法,对于一个给出的N让我们求1 - N之间有多少个数满足F(x)为偶数的情况,输出这个数. ...

  7. LightOJ 1341 Aladdin and the Flying Carpet(整数拆分定理)

    分析:题目并不难理解,就是一些细节上的优化需要我们注意,我在没有优化前跑了2000多MS,优化了一些细节后就是400多MS了,之前还TLE了好几次. 方法:将整数拆分为质因子以后,表达为这样的形式,e ...

  8. HDU1028 (整数拆分)

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  9. 整数拆分问题_C++

    一.问题背景  整数拆分,指把一个整数分解成若干个整数的和 如 3=2+1=1+1+1  共2种拆分 我们认为2+1与1+2为同一种拆分 二.定义 在整数n的拆分中,最大的拆分数为m,我们记它的方案数 ...

  10. Pollard-Rho大整数拆分模板

    随机拆分,简直机智. 关于过程可以看http://wenku.baidu.com/link?url=JPlP8watmyGVDdjgiLpcytC0lazh4Leg3s53WIx1_Pp_Y6DJTC ...

随机推荐

  1. Linux 处理CPU和内存参数的方式总结

    Linux 处理CPU和内存参数的方式总结 关闭NUMA,关闭透明大页 比较简单的方法: vim /etc/default/grub 在 GRUB_CMDLINE_LINUX 里面添加配置: tran ...

  2. 是否开启超线程对CPU不同命令的影响情况

    背景 最近公司购买了一台服务器, 要进行一次性能测试. 基于此, 我这边进行了一下超线程与否的测试验证 使用stress-ng的命令,对所有的 CPU 方法进行测试 然后只分析 bogo ops/s ...

  3. 文盘Rust -- r2d2 实现redis连接池

    作者:贾世闻 我们在开发应用后端系统的时候经常要和各种数据库.缓存等资源打交道.这一期,我们聊聊如何访问redis 并将资源池化. 在一个应用后端程序访问redis主要要做的工作有两个,单例和池化. ...

  4. 对于Vue3和Ts的心得和思考

    作者:京东物流 吴云阔 1 前言 Vue3已经正式发布了一段时间了,各种生态已经成熟.最近使用taro+vue3重构冷链的小程序,经过了一段时间的开发和使用,有了一些自己的思考. 总的来说,Vue3无 ...

  5. 【解决了一个小问题】terraform创建service后,如何获取VIP的值?

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 创建一个pod后,再为这个pod创建一个对应的servic ...

  6. 人均瑞数系列,瑞数 5 代 JS 逆向分析

    声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容.敏感网址.数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 本文章未经许 ...

  7. ABP系列文章收藏

    1.ASP.NET样板开发框架ABP系列之ABP入门教程详解: https://www.php.cn/csharp-article-380181.html 2.官网中文翻译:  https://www ...

  8. vim 从嫌弃到依赖(12)——打开及保存文件

    在前几篇文章中,我们从vim各种模式的使用着手介绍了vim如何进行文本本身的编辑.也通过缓冲区列表的介绍了解到了vim是如何进行打开文件的管理.这篇我们将会着眼于文件的打开和保存的基本操作.通过这篇的 ...

  9. 服务器重装ip未更改,ssh连不上(WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED)

    服务器重装ip未更改,ssh连不上 前言 原因 解决方法 服务器重装ip未更改,ssh连不上 前言 重装了虚拟机,ip还保留了,但是发现连不上了 @@@@@@@@@@@@@@@@@@@@@@@@@@@ ...

  10. 【1】paddle飞桨框架高层API使用讲解

    1.高层API简介 飞桨框架2.0全新推出高层API,是对飞桨API的进一步封装与升级,提供了更加简洁易用的API,进一步提升了飞桨的易学易用性,并增强飞桨的功能. 飞桨高层API由五个模块组成:数据 ...