题目 <https://leetcode-cn.com/problems/target-sum/>
终于终于终于能够自己分析
状态,2个:前n个数,和
转移:+nums[i],-nums[i]
dp[i][j]表示前i个数和为j (范围[-sum~sum])的方法数,因为数组没有负数,需要+sum偏移 [0,2sum]
有些地方思考了很久,偏移+sum那里,可以看看注释
int findTargetSumWays(int* nums, int numsSize, int S){
int sum = 0,i,j;
for(i=0;i<numsSize;i++){
sum += nums[i];
}
if(sum < S){
return 0;
}
//printf("sum%d\n",sum);
int **dp = malloc(sizeof(int*) * numsSize);//dp[i][j]表示前i个数和为j[-sum~sum]的方法数
for(i=0;i<numsSize;i++){
dp[i] = malloc(sizeof(int) * (sum*2+1));//[-sum~sum]=>[0~2sum]
}
/*
for(i=-sum;i<=sum;i++){
printf("%2d, ",i);
}
printf("\n");
*/
for(i=0;i<1;i++){//前1个数和为j的方法数
for(j=0;j<=sum*2;j++){
dp[i][j] = 0;
//k+nums[i]+sum == j//前置和k==0
if(-nums[i]+sum == j){
dp[i][j]++;
}
//k-nums[i]+sum == j//前置和k==0
if(nums[i]+sum == j){
dp[i][j]++;
}
//printf("%2d, ",dp[i][j]);
}
//printf("\n");
}
for(i=1;i<numsSize;i++){//前i个数和为j的方法数
for(j=0;j<=sum*2;j++){
dp[i][j] = 0;
//错误k+nums[i]+sum == j
//正确k+nums[i] == j//前置和是k,明白了k早就带了sum的偏移
if((j-nums[i]) >= 0 && (j-nums[i])<=2*sum){
dp[i][j] += dp[i-1][j-nums[i]];
}
//错误k-nums[i]+sum == j
//正确k-nums[i] == j//前置和是k
if((j+nums[i]) >= 0 && (j+nums[i]) <=2*sum){
dp[i][j] += dp[i-1][j+nums[i]];
}
//printf("%2d, ",dp[i][j]);
}
//printf("\n");
}
j = dp[numsSize-1][S+sum];
for(i=0;i<numsSize;i++){
free(dp[i]);
}
free(dp);
return j;
}