题目关键信息:
给定一个数组,将数组分成两个部分,使得这两部分的和的差最小
方法一:动态规划
“数组”,“求最优值”显然这道题可以用动态规划解决,这是0-1背包的变形类题目,求数组两部分的和的差的最小值,假设数组的总和为,部分一的和为
,部分二的和为
,那么
增加,
就减小,
减小,
就增加,
,因此背包的最大容量是
,只有当
不断接近
时,他们的差才会最小,于是,我们将问题转化为,在
的背包容量中,怎样放置物品才能使尽可能地填满背包。
明确了可选物品的数量是数组的大小,背包的最大容量是后,我们定义
数组,明确
数组的含义,
的含义就是背包容量是j的情况是背包内所装的前
个物品的最大价值。
:背包容量装不下第
个礼物,不装下,继承
的值
背包容量装得下第
个物品,在装下与不装下中选择最大值,即
Java版本
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param presentVec int整型一维数组 每个礼物的价值
* @return int整型
*/
public int maxPresent (int[] presentVec) {
// write code here
int sum=0;
for(int i=0;i<presentVec.length;i++){
sum+=presentVec[i];
}
//背包总容量为sum/2
int m=presentVec.length,n=sum/2;
//dp[i][j]表示在背包容量为j的情况下,背包里前i个物品所具有的最大价值
int[][]dp=new int[m+1][n+1];
//遍历背包中的物品
for(int i=1;i<=m;i++){
//遍历背包的容量
for(int j=1;j<=n;j++){
//第i件物品的容量大于背包容量
if(presentVec[i-1]>j){
dp[i][j]=dp[i-1][j];
}else{
//在装入与不装入之间取最大值
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-presentVec[i-1]]+presentVec[i-1]);
}
}
}
return Math.abs(sum-2*dp[m][n]);
}
}C++版本
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param presentVec int整型vector 每个礼物的价值
* @return int整型
*/
int maxPresent(vector<int>& presentVec) {
// write code here
int sum=0;
for(int i=0;i<presentVec.size();i++){
sum+=presentVec[i];
}
//背包总容量为sum/2
int m=presentVec.size(),n=sum/2;
//dp[i][j]表示在背包容量为j的情况下,背包里前i个物品所具有的最大价值
vector<vector<int>>dp(m+1,vector<int>(n+1));
//遍历背包中的物品
for(int i=1;i<=m;i++){
//遍历背包的容量
for(int j=1;j<=n;j++){
//第i件物品的容量大于背包容量
if(presentVec[i-1]>j){
dp[i][j]=dp[i-1][j];
}else{
//在装入与不装入之间取最大值
dp[i][j]=max(dp[i-1][j],dp[i-1][j-presentVec[i-1]]+presentVec[i-1]);
}
}
}
return abs(sum-2*dp[m][n]);
}
};复杂度:
时间复杂度:外层循环次,内层循环
次,时间复杂度为
空间复杂度:额外创建的数组大小为
,复杂度为
优化后的动态规划的状态只和
的状态有关,我们可以采用滚动数组,将二维
数组压缩为一维,具体做法是只保留j这个维度,每一次在遍历第i个物品时,
保存着遍历完前i个物品后背包的价值,即
还没被新结果覆盖时相当于
相当于二维数组中的
,为什么这里的j要从后往前遍历呢?因为如果j从前往后遍历,当i不变时,前面已经计算过的
会覆盖后面的
的意义不等于二维数组中的
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param presentVec int整型一维数组 每个礼物的价值
* @return int整型
*/
public int maxPresent (int[] presentVec) {
// write code here
int sum=0;
for(int i=0;i<presentVec.length;i++){
sum+=presentVec[i];
}
//背包总容量为sum/2
int m=presentVec.length,n=sum/2;
//dp[i][j]表示在背包容量为j的情况下,背包里前i个物品所具有的最大价值
int[]dp=new int[n+1];
//遍历背包中的物品
for(int i=1;i<=m;i++){
//j要从后往前遍历,否则当i不变时,前面已经计算过的dp[j-presentVec[i-1]]会覆盖后面的dp[j-presentVec[i-1]]
//dp[j-presentVec[i-1]]的意义不等于二维数组中的dp[i-1][j-presentVec[i-1]],边界条件是背包容量要装得下第i个物品
//遍历第i个物品时,dp[j]保存着遍历完前i个物品后背包的价值,即dp[j]还没被新结果覆盖时相当于dp[i-1][j]
for(int j=n;j>=presentVec[i-1];j--){
dp[j]=Math.max(dp[j],dp[j-presentVec[i-1]]+presentVec[i-1]);
}
}
return Math.abs(sum-2*dp[n]);
}
}复杂度:
时间复杂度:外层循环次,内层循环
次,时间复杂度为
空间复杂度:额外创建的数组大小为
,复杂度为

京公网安备 11010502036488号