LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

动态规划整数拆分题目感悟

题目如下:
https://leetcode.cn/problems/partition-equal-subset-sum/

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

这里整数拆分的题目,代码随想录处理的并不好。但是依旧有借鉴意义。
我们这里只讲它的动态规划的代码(也就是它附加的第一个代码)
动态规划的核心是
dp数组的记忆与递归公式的结合使用
这个整数拆分的dp数组记忆很简单,这里就不多说,我只说它的递推公式
dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j))
他这里实际上有冗余,因为他是根据他第三个思路不清但是通过了的代码改过来的实际上应该是这样的
dp[i] =max((i - j) * j, dp[i - j] * j)
我们理解递推公式,甚至思考递推公式要保持的这样一个思路:
最后一步是怎样由倒数第二步推导出来的
或者上面那种说法强调了由倒数第二步推导,不够清楚,因为很多,比如说这里的这个问题就不完全是根据倒数第二步的结果dp[i-1],推导出来的,而是综合了dp[i-1]和其他已知条件推导出来的
或者我们可以这样说:

最后一步是可以拆分成怎样的由已知条件的比较,简单计算而获得的结果

我们用这样一个思路来解释这个递推公式:最后一步,求i的拆分之后相乘的最大值就是可以通过拆成两个数相乘与多个数相乘两种互斥情况,之后比较求最大值来获得(这里但凡拆分之后,所要求的拆分之后每一个部分的最大值我们是已知的)

而拆成多个数我的最初思路是会有两种情况,拆成两个数之后其中一个数拆另外一个数不拆,与两个数都拆两种情况
所以递推公式应该是:
dp[i] =max((i - j) * j, dp[i - j] * j,dp[i-j]dp[j])
即还应多有两个数都拆的这种情况dp[i-j]dp[j]
其实仔细一想,由于j从1到i-1,他的代码是从1到i-2,是因为他要适应没有dp[1]这种情况导致不能出现dp[i-(i-1)]
由于确实最终求最大值不会出现拆出1
xxx
xxx这种无用选项,所以这种算法是没毛病的,(我们从1开始是要适应会出现1i-1这种情况,所以必须从1开始,而(i-1)(i-(i-1))其实已经算过了,其实只要j大于i/2,(i - j) * 就都是重复的了)
回到我们最初说的,由于j从1到i-1,当j小的时候其实就相当于两个都拆,所以这种一边拆一边不拆的情况其实是覆盖两边都拆的情况的,这也就解释了我们做任何整数拆分题目时(无论是加拆分还是乘拆分,这里是加拆分,之后的乘是加拆分不同情况之下对应的结果)都总是一边从1到i-1,另外一边拆了

showimg