Day 43 | 1049. 最后一块石头的重量 II & 494. 目标和 & 474.一和零

1049. 最后一块石头的重量 II

 本题和上一题子集和比较类似,就是比较难想到用背包问题解题,写代码过程还是很顺畅的。。

一维01背包解题思路:

        本题可以看成容量为target=sum/2的背包,尽可能往里装石头,石头的重量和价值都为stones【i】,最多可以装dp[j]的石头,则剩下了sum-dp[target]的石头,最后两者取差值,即为结果。

        因为sum/2为向下取整,因此dp[target]<=sum/2,因此sum-dp-dp即为本题结果。

    public int lastStoneWeightII(int[] stones) {
        int sum=0;
        for(int i:stones){
            sum+=i;
        }
        int target=sum/2;
        int[] dp=new int[target+1];
        for(int i=0;i<stones.length;i++){
            for(int j=target;j>=stones[i];j--){
                dp[j]=Math.max(dp[j],dp[j-stones[i]]+stones[i]);
            }
        }
        return sum-dp[target]-dp[target];
    }

 494. 目标和 

 

。。。让我学会放弃,快哭了

https://leetcode.cn/problems/target-sum/solutions/1303046/hen-xiang-xi-de-zhuan-hua-wei-0-1bei-bao-irvy/

        这个题解挺清晰的,我大概能看懂,但是她的数组定义区间为0-i,就让我我看不懂初始化的过程和为什么是nums[i-1],然后我自己尝试转化成]0i-1]出错了,真挺崩的,哈哈。

说一下我理解的解题思路:

        nums数组中,所有i的和为sum,所有整整数和为A,负整数(取绝对值)和为B。那么可以得出:

        ①A+B=sum  ②A-B=target

        综上所述,可得A=(sum+target)/2

        因此可将本题转化为,[0,i]个物品,每个物品重量为nums[i],使其和为(sum+target)/2共有多少种取法(有多少种方法能将容量为A的背包填满)?

        注意:sum和target都为正整数,因此和一定为偶数,若target+sum不为偶数,直接返回0即可。

        dp[i][j]含义:从[0,i]中取数,和为j,有dp[i][j]种取法

每次有两种选择:

①取

dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]];  //不取的方法+取的方法总和

②不取(j<nums[i-1])

dp[i][j] = dp[i - 1][j] 

代码我就贴个正确版。。照抄的。。自己没做出来。。

    public int findTargetSumWays(int[] nums, int target)
    {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        int bagSize = (target + sum) / 2;
        if (bagSize < 0) bagSize = -bagSize;
        //如果target + sum为奇数,则无解
        if ((target + sum) % 2 == 1) return 0;

        int[][] dp = new int[nums.length + 1][bagSize + 1];
        for (int i = 0; i <= nums.length; i++) {
            dp[i][0] = 1;
        }
        for (int i = 1; i <= nums.length; i++) {
            for (int j = 0; j <= bagSize; j++) {
                if (j >= nums[i - 1])
                    dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
                    //很多人不理解这里为什么是nums[i - 1]
//  这是因为第一层for中的i从1开始,i-1是为了让nums[]从第一个元素开始遍历,是对齐操作
                else
                    dp[i][j] = dp[i - 1][j];
            }
        }
        return dp[nums.length][bagSize];
    }

 474.一和零

 题我是真看不太明白。。看代码都没看懂。。看题解也没看懂。。真让我有点怀疑自己了救命。。希望二刷能弄清楚

01背包解题思路:

        本题可以看作是有两个维度的背包问题。

dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]

我这里是真看不懂。。二刷让我把数组都推一遍。。。

 

    public int findMaxForm(String[] strs, int m, int n) {
        //dp[i][j]表示i个0和j个1时的最大子集
        int[][] dp = new int[m + 1][n + 1];
        int oneNum, zeroNum;
        for (String str : strs) {
            oneNum = 0;
            zeroNum = 0;
            for (char ch : str.toCharArray()) {
                if (ch == '0') {
                    zeroNum++;
                } else {
                    oneNum++;
                }
            }
            //倒序遍历
            for (int i = m; i >= zeroNum; i--) {
                for (int j = n; j >= oneNum; j--) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
                }
            }
        }
        return dp[m][n];
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值