目标和问题---动态规划+背包问题+数学
思路
数学推导:
将数组随机分为两部分,第一部分和为left
,第二部分和为right
,数组总和为sum
,目标和为target
。
可以得到:
left+right=sum
left-right=target
可以推出:
left=(sum+target)/2 或者 right=(sum-target)/2
以上两种选择都可以通过,我选择第二种 diff=sum-target
- 如果
diff<0
显然不成立,因为所有元素都是非负数 - 如果
diff
为奇数也不成立,应为所有元素都为整数,相加不可能有小数
综上所述,可以将问题转化为背包问题,将容量为left的背包装满有多少种方式。
背包问题:装满背包有多少种方式。
dp[i][j]的含义:有i件物品,背包容量为j时,装满背包最多有多少种;
- 当j<num[i-1]时,只有一种情况,不装第i件物品,即有i-1件物品,容量为j时,装满有多少种情况,dp[i][j]=dp[i-1][j].
- 当j>=nums[i-1]时,有两种情况,装和不装第i件物品,总方式有这两种情况相加得到,d[i][j]=d[i-1][j]+dp[i-1][j-nums[i-1]]
- 注意:nums数组下表从0开始,循环从1开始。
代码
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int n = nums.size();
int sum = 0;
for (int a : nums)sum += a;//所有数的和
//如果为奇数,不存在目标和为target的情况
if (sum - target<0||(sum + target) % 2 == 1)return 0;
//dp[i][j]的含义:当有i个数,目标和为j时,装满背包的方式最多有多少种
int dp[1010][1010] = { 0 };
int m = (sum - target) / 2;
//初始化dp
dp[0][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
if (nums[i-1] > j)
{
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = dp[i - 1][j - nums[i - 1]] + dp[i - 1][j];
}
}
}
return dp[n][m];
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端