【力扣刷题】整数拆分(动态规划)

简介: 动态规划其基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,经分解得到子问题往往不是互相独立的,举个简单的例子:你知道两个1相加等于2,问你三个1相加你是拿前面的两个1相加的结果加上1呢,还是再用1+1+1,你肯定会用前面的那种方法对吧,这就是动态规划,(1+1)就是(1+1+1)的子问题,且并不是相互独立,你得到了(1+1)就好得到(1+1+1)了

动态规划

其基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,经分解得到子问题往往不是互相独立的,举个简单的例子:你知道两个1相加等于2,问你三个1相加你是拿前面的两个1相加的结果加上1呢,还是再用1+1+1,你肯定会用前面的那种方法对吧,这就是动态规划,(1+1)就是(1+1+1)的子问题,且并不是相互独立,你得到了(1+1)就好得到(1+1+1)了

整数拆分
题目
给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k >= 2 ),并使这些整数的乘积最大化。

返回 你可以获得的最大乘积 。

示例 1:

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

输入: n = 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

提示:

2 <= n <= 58

思路
对于正整数 n,当 n≥2 时,可以拆分成至少两个正整数的和。令 x 是拆分出的第一个正整数(取值范围为1~(n-1)),则剩下的部分是 n-x

n-x有两种情况 :

1.不可以继续拆分,那么乘积就是x*(n-x)

2.可以继续拆分成至少两个正整数的和,那么乘积就是x((n-x)的乘积最大化),将子问题求的解即将2到n的所有乘积最大化存入数组dp[n]中,那么乘积就是xdp[n-x]

用for循环按照上面的方法求2~n的乘积最大化,比如:

求2的乘积最大化:

不可以继续拆分,乘积是1*(2-1)为1

求3的乘积最大化:

可以拆分为1和2,2不拆分的乘积为2,拆分的乘积为1*dp[3-1]也就是1,取不拆分的乘积和拆分的乘积的最大值为2

求4的乘积最大化:

可以拆分为1和3,3不拆分的乘积为3,拆分的乘积为1*dp[4-1]也就是2,取不拆分的乘积和拆分的乘积的最大值为3

可以拆分为2和2,2不拆分的乘积为4,拆分的乘积为2*dp[4-2]也就是2,取不拆分的乘积和拆分的乘积的最大值为4

这和上面两个不一样,它可以拆分为1和3,2和2两种情况,所以要求1和3,2和2之间的最大值为4

依次类推......

因为求最大值的功能经常使用,使用用三目运算符?:写个求最大值的函数Max()

由于每个正整数对应的最大乘积取决于比它小的正整数对应的最大乘积,因此可以使用动态规划求解。

代码

#include <stdio.h>
int Max(int i, int j);
 
int main() {
    int n;
    printf("n=");
    scanf("%d", &n);
    int dp[n] = {0, 0};
 
    for (int i = 2; i <= n; i++) {
        int max = 0;
 
        for (int j = 1; j < i; j++) {
            max = Max(max, Max(j * (i - j), j * dp[i - j]));
        }
 
        dp[i] = max;
    }
 
    printf("%d", dp[n]);
    return 0;
}
 
int Max(int i, int j) {
    return i > j ? i : j;
}

执行结果

image.png

为了更好的观察 ,可以在

dp[i] = max;

后面加个

printf("%d\n", dp[i]);

可以看到2~10所有的乘积最大化

image.png

创建数组dp时,其中dp[i] 表示将正整数 i 拆分成至少两个正整数的和之后,这些正整数的最大乘积。特别地,00 不是正整数,11 是最小的正整数,00 和 11 都不能拆分,因此dp[0]和dp[1]一定要赋值为0,如果不赋值为0,直接int dp[n];就会出现以下状况

image.png

赋初值为0:
image.png

相关文章
|
12天前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
25 6
|
12天前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
26 4
|
12天前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
37 2
|
12天前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
15 7
|
12天前
|
Python
【Leetcode刷题Python】剑指 Offer 30. 包含min函数的栈
本文提供了实现一个包含min函数的栈的Python代码,确保min、push和pop操作的时间复杂度为O(1)。
12 4
|
13天前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
31 5
|
12天前
|
算法 Python
【Leetcode刷题Python】 LeetCode 2038. 如果相邻两个颜色均相同则删除当前颜色
本文介绍了LeetCode 2038题的解法,题目要求在一个由'A'和'B'组成的字符串中,按照特定规则轮流删除颜色片段,判断Alice是否能够获胜,并提供了Python的实现代码。
22 3
|
12天前
|
算法 Python
【Leetcode刷题Python】剑指 Offer 33. 二叉搜索树的后序遍历序列
本文提供了一种Python算法,用以判断给定整数数组是否为某二叉搜索树的后序遍历结果,通过识别根节点并递归验证左右子树的值是否满足二叉搜索树的性质。
10 3
|
12天前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - II. 从上到下打印二叉树 II
本文提供了一种Python实现方法,用于层次遍历二叉树并按层打印结果,每层节点按从左到右的顺序排列,每层打印到一行。
22 3
|
13天前
|
Python
【Leetcode刷题Python】剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
Leetcode题目"剑指 Offer 21. 调整数组顺序使奇数位于偶数前面"的两种Python解决方案,一种是使用双端队列调整数组顺序,另一种是使用双指针法将奇数移到数组前半部分,偶数移到后半部分。
15 4