494. 目标和 Target Sum

题目 <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;
}

猜你喜欢

转载自blog.csdn.net/ZRXSLYG/article/details/111713202