子集划分是个什么东西?背包问题->动态规划?
子集划分问题抽取
以上题目来自力扣494.目标和,本篇文章的重点在于提取出其中的一种类型问题,称为子集划分问题。
所谓子集划分问题,是一个典型的背包问题,而背包问题,使用的是动态规划来解决。此题可以使用回溯方法来做,但由于一些重复的计算,时间复杂度会很高,因此可以转化为背包问题从而使用动态规划来解决来降低复杂度。
子集划分问题解决思路
子集划分问题,其实就是我们把nums数组分成两个子集A和B,分别代表分配+和分配-的数,那么他们和S会存在以下关系:
//加数和-减数和等于目标值
sum(A)-sum(B)=S
sum(A)=S+sum(B);
//两边同时加上A的和
sum(A)+sum(A)=S+sum(B)+sum(A);
2*sum(A)=S+sum(nums)
那我们可以推出sum(A)=(target + sum(nums) ) / 2,也就把原问题转化为,在nums中能寻找到多少个子集,满足子集和等于目标值+nums集合和的一半?
那么我们可以实现以下两个函数来解决此类问题:
//计算nums中有几个子集的和为sum
int howManySubsets(int[] nums,int sum){
int n=nums.length;
//dp[i][j]=x表示在前i个物品中选择,若当前背包容量为j,则最多有x种方法能恰好装满背包
int[][] dp=new int[n+1][sum+1];
for(int i=0;i<=n;i++){
//dp[..][0]=1 如果背包最大载重为0 那什么都不装是一种
//dp[0][..]=0 没有物品,则无法装包
dp[i][0]=1;