代码随想录第四十三天|最后一块石头的重量、目标和、一和零

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

题目链接: 最后一块石头的重量 II
自己的思路:想不到是背包问题!!!

正确思路:这道题让我们找撞击以后的石头的重量的最小值,其实这个题主要是要做个转换,转换成一个背包问题,那么怎么转换呢,我们可以思考把这堆石头分成两堆,两堆的重量极其接近的时候相互撞击就会得到最小重量的石头,也就是和之前那道题一样,将每一堆的石头的重量都尽可能地接近sum(石头重量总和)/2,这样分完以后有一堆是dp[sum/2],另一堆就是sum-dp[sum/2],一定是后者大或者相等,因为除以2是向下取整;动态规划五部曲:1、dp数组的含义:dp[i]表示容量为i的背包最多可以盛放多少重量(本题重量=价值)的物品;2、递推公式:dp[i]=max(dp[i],dp[i-stones[i]]+stones[i])也就是一维背包的公式;3、dp数组的初始化,由于是找最大的值,所以还是一样都初始化为0;4、遍历顺序:由于每个数只能使用一次,所以背包从后向前遍历;5、打印dp数组:主要用于debug!!!那么最后得出来结果以后dp[sum/2]就是我们要的结果,然后用
sum-2*dp[sum/2]返回结果即可!!
代码:

class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for (int num:stones){
            sum += num;
        }
        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-2*dp[target];
    }
}

Leetcode 494. 目标和

题目链接: 目标和
自己的思路:想不到递推公式!!!

正确思路:这道题还是一个0-1背包问题,但是就是不知道怎么想如何去转换;首先这道题让找正数和负数的组合,其和为target,那其实就相当于正数的情况,我们先假设正数这波总和为posi,负数的绝对值总和为nega,那么会有以下两个等式,也就是posi+nega=sum;posi-nega=target;联立这两个公式,我们是可以得到posi=(sum+target)/2的,这个也就是正数的和,也就是说从这些数里面如果我们能找到一些数的和为posi,那么就是一种情况,那么就变成了一个0-1背包问题;动规五部曲:1、dp数组的含义:dp[i]表示正数和为i的时候,所找到的数的情况;2、递推公式:这里我们假设这样一个情况,当固定一个数nums[j]的时候,能凑成总和为i的情况有多少种,其实是dp[i-nums[j]],那么当固定nums[j+1]的时候,能凑成总和为i的情况有dp[i-nums[j+1]]种,所以dp[i]是对所有dp[i-nums[j]]的累加和;3、dp数组初始化,这里我们初始化数组dp[0]=1,因为这样对本题比较合理(不要思考具体含义);4、遍历顺序:因为每个数字只能使用一次,所以我们从后向前遍历背包;5、打印dp数组:主要用于debug!!!

代码:

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        
        int sum = 0;
        for (int num:nums){
            sum += num;
        }
        //出现较小的target
        if (target<0 && sum<-target) return 0;
        //正数的个数
        if ((sum+target)%2!=0) return 0;
        int size = (sum+target)/2;
        int[] dp = new int[size+1];
        dp[0]=1;
        for (int i =0;i<nums.length;i++){
            for (int j=size;j>=nums[i];j--){
                //递推公式
                dp[j] += dp[j-nums[i]];
            }
        }
        return dp[size];

    }
}

Leetcode 474. 一和零

题目链接: 一和零
自己的思路:想不出来!!

正确思路:这道题是看不太出来是一个0-1背包问题,因为过于隐晦,仔细的读题目其实可以发现,我们可以m和n当成背包,那么题目就变成了这个背包最多可以放多少个字符串了,那么字符串就变成了我们的物品,那么具体的物品是什么呢,就是每个字符串里面的0和1字符的数量;动态规划五部曲:1、dp数组的含义:dp[i][j]表示有i个0和j个1最多可以装多少字符串;2、递推公式:我们可以思考一下,dp[i][j]是由当前要选的这个字符串str决定的,我们可以把它里面含有的0的数量记为zeroNum,含有的1的数量记为oneNum,那么我们不选这个字符串的话最大的个数为dp[i-zeroNum][j-oneNum],那么如果选了这个字符串的话,那么最大的个数就是dp[i-zeroNum][j-oneNum]+1,这个题每个字符串(物品)的价值都是1,因为要求的是最大的字符串个数,所以我们要在它和dp[i][j]之间选一个最大值来赋值给dp[i][j];3、dp数组初始化:因为是求非负数的最大值,那么我们可以把所有的数都初始化为0;4、遍历顺序:因为每个物品只能选一次,我们从后向前遍历背包;5、打印dp数组:主要用于debug!!!!

代码:

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        int zeroNum,oneNum;
        //遍历物品
        for (String str:strs){
            zeroNum = 0;
            oneNum = 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];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值