代码随想录算法训练营第四十三天|1049. 最后一块石头的重量 II 、494. 目标和 、474.一和零

目录

1049. 最后一块石头的重量 II (0-1背包)

二维dp数组

一维dp数组(没有二维好理解)

494. 目标和 

474.一和零(先不做)


1049. 最后一块石头的重量 II (0-1背包)

题目链接:1049. 最后一块石头的重量 II

老觉得这个题可以排序、做差什么的用贪心来做!看过题解发现确实有,倒还不如转为为0-1背包。

二维dp数组

int calculate_sum(int* stones, int stonesSize){
    int sum=0;
    for(int i=0;i<stonesSize;i++){
        sum+=stones[i];
    }
    return sum;
}
int lastStoneWeightII(int* stones, int stonesSize){
    int sum=calculate_sum(stones,stonesSize);
    int target=sum/2;
    int dp[stonesSize][target+1];
    //初始化dp数组
    for(int i=0;i<stonesSize;i++){
        dp[i][0]=0;
    }
    int i=0;
    for(;i<target&&i<stones[0];i++){
        dp[0][i]=0;
    }
    for(;i<=target;i++){
        dp[0][i]=stones[0];
    }
    //填充dp数组
    for(int i=1;i<stonesSize;i++){
        for(int j=1;j<=target;j++){
            if(j-stones[i]>=0){
                dp[i][j]=fmax(dp[i-1][j],dp[i-1][j-stones[i]]+stones[i]);
            }else{
                dp[i][j]=dp[i-1][j];
            }
        }
    }

    return fabs(2*dp[stonesSize-1][target]-sum);
}

一维dp数组(没有二维好理解)

int calculate_sum(int* stones, int stonesSize){
    int sum=0;
    for(int i=0;i<stonesSize;i++){
        sum+=stones[i];
    }
    return sum;
}
int lastStoneWeightII(int* stones, int stonesSize){
    int sum=calculate_sum(stones,stonesSize);
    int target=sum/2;
    int* dp=(int*)malloc(sizeof(int)*(target+1));
    memset(dp,0,sizeof(int)*(target+1));
    for(int i=0;i<stonesSize;i++){
        for(int j=target;j>=stones[i];j--){
            dp[j]=fmax(dp[j],dp[j-stones[i]]+stones[i]);
        }
    }
    return fabs(2*dp[target]-sum);
}

494. 目标和 

题目链接:494. 目标和

题目描述:

给你一个整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

    例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

这些应用题要想到怎么转化成0-1背包的问题真难呀!

        nums数组中一部分元素取正,一部分元素取负有如下两个等式成立:(等式左边两求和的元素没有正负之分,只取元素值)

                                                \sum \left ( + \right )+\sum \left ( - \right )=\sum nums[i]

                                                   \sum \left ( + \right )-\sum \left ( - \right )=target

        由上面两个等式得出:

                                             \sum\left ( + \right )=(\sum\left ( nums[i] \right )+target)/2

        等式右边值可求得,就能转化为0-1背包问题:nums数组中子集和=目标值有几种方案

        递推公式:

                                                dp[j]=\sum \left ( dp[j-nums[i]] \right )

int calculate(int* nums,int numsSize,int target){
    int sum=0;
    for(int i=0;i<numsSize;i++){
        sum+=nums[i];
    }
    return sum+=target;
}
int findTargetSumWays(int* nums, int numsSize, int target){
    int sum=calculate(nums,numsSize,target);
    if(sum<0||sum%2)   return 0;
    sum/=2;

    int* dp=(int*)malloc(sizeof(int)*(sum+1));
    memset(dp,0,sizeof(int)*(sum+1));
    //dp[0]要初始化为1
    dp[0]=1;
    for(int i=0;i<numsSize;i++){
        for(int j=sum;j>=nums[i];j--){
            dp[j]+=dp[j-nums[i]];
        }
    }
    return dp[sum];
}

474.一和零(先不做)

死乞白赖做了也白做!不会还是不会,前面都没学好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值