最近开始写动态规划了,题解都少写好多!!!为啥呢?太tm难了,有些题看了题解还要想个几小时。终究还是菜狗!!
不说了,继续写题解,加深理解
第一种解法:回溯
这个就不用我写了吧,感觉没有技术含量。用回溯我都感觉很愧疚,因为跟暴力差不多。但是没办法,不会就老老实实写这种了
class Solution {
int sum=0;
public int findTargetSumWays(int[] nums, int target) {
int length=nums.length;
dfs(nums,target,length,0,0,0);
return sum;
}
private void dfs(int[] nums, int target, int length,int flag,int totalSum,int total) {
if(total==length&&totalSum==target){
sum++;
return;
}
if(total<length){
total++;
totalSum=totalSum+nums[flag];
dfs(nums,target,length,flag+1,totalSum,total);
totalSum=totalSum-nums[flag];
totalSum=totalSum-nums[flag];
dfs(nums,target,length,flag+1,totalSum,total);
total--;
totalSum=totalSum+nums[flag];
}
}
}
第二种解法: 动态规划(在这之前需要你掌握0/1背包)
一开始就是一个难点:
先将这些数全部加起来为sum(不包含符号),我们假设选出来的数中正数和为x,那么其选出来的负数和就为sum-x(注意:这里的sum,x都是无符号的数,也就是正数
)
那么题目给出的target=-(sum-x)+x(这里负数和+正数和为目标和嘛)
,之后给它变式一下为:x=(target+sum)/2,其中target和sum是不变的,那么你看到这里是不是明白了什么??
题目其实就变成是:我们需要从数组中找出和为x有几种组合方式(这样的话就把什么负数的给去掉了,不然搞得很麻烦一样)
如果你比较了解0/1背包的话,相信你已经有思路了,就变成了容量为x的背包有几种装法。
二维的动态规划dp[i][j]表示的含义为:从下标为0-i的数中,和为j的组合方式有dp[i][j]种
滚动数组的动态规划dp[j]表示的含义为:装满j的组合方式有dp[j]种
我们用滚动数组来做时,一定要想到二维的dp数组表示什么意思,这样就不容易搞乱
dp[0]表示容量为0的背包只有一种装法,那就是不装。故dp[0]=1
故而动态规划方程为:dp[j]=dp[j-nums[i]]+dp[j];(表示不装num[i]这个元素时的组合个数+装num[i]元素的组合个数)
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum=0;
for(int x:nums)
sum+=x;
if((sum+target)%2!=0||sum+target<0)
return 0;
int[] dp=new int[(sum+target)/2+1];
dp[0]=1;
for(int i=0;i<nums.length;++i){
for(int j=(sum+target)/2;j>=nums[i];--j){
dp[j]=dp[j-nums[i]]+dp[j];
//System.out.print(dp[j]+" "+j+"///");
}
//System.out.println();
}
return dp[(sum+target)/2];
}
}