整数拆分

力扣题目链接(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. [转帖]Kdump调试机理详细总结(一)

    https://blog.csdn.net/luckiers/category_11796393.html 一.简介 本文主要讲解Kdump的运行机理,后续两个章节会详细介绍kdump的使用和如何分析 ...

  2. [转帖]【k8s】1、基础概念和架构及组件

    文章目录 一.kubernetes概述 1.什么是kubernetes? 2.应用程序部署方式的演变 3.为什么要用kubernetes? 二.kubernetes 特性 三.Kubernetes集群 ...

  3. [转帖]JAVA之G1垃圾回收器

    https://www.cnblogs.com/boanxin/p/12292331.html 概述 G1 GC,全称Garbage-First Garbage Collector,通过-XX:+Us ...

  4. 使用telnet来调试游戏

    telnet是什么 Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用户提供了在本地计算机上完成远程主机工作的能力 但是,telnet因为采用明文 ...

  5. go中bufio使用小结

    bufio 前言 例子 bufio 源码解析 Reader对象 实例化 ReadSlice ReadString ReadLine Peek Scanner Give me more data Err ...

  6. Python 排序与查找算法收集

    Python 语言实现几种不同的排序算法,代码来自于老男孩Python全栈开发,学习教程! import random import time import copy import sys def c ...

  7. Linux 多种方式实现文件共享

    文件共享服务在Linux系统上有多种方式,最常用的有Samba,vsftp,iSCSI,NFS这四种方式,如下将分别配置四种不同的文件共享服务. VSFTP 文件传输 FTP是文件传输协议.用于Int ...

  8. Docker从认识到实践再到底层原理(三)|Docker在Centos7环境下的安装和配置

    前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...

  9. 【文件】C语言文件操作及其使用总结篇【初学者保姆级别福利】

    [文件]C语言文件操作及其使用总结篇[初学者保姆级别福利] 一篇博客学好动态内存的管理和使用 这篇博客干货满满,建议收藏再看哦!! 求个赞求个赞求个赞求个赞 谢谢 先赞后看好习惯 打字不容易,这都是很 ...

  10. 如何进行IIS性能优化,提高应用并发能力

    2021-03-05 先附上IIS的官方文档,如果你的英文阅读能力不错的话,直接阅读官方文档,更加清楚明白: https://docs.microsoft.com/zh-cn/iis/get-star ...