Day43| Leetcode 1049. 最后一块石头的重量 II Leetcode 494. 目标和 Leetcode 474. 一和零

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

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

本题思路用一句话概括本题:其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小。这样一看和前面的题目一个思路了,下面上代码:

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int sum = 0;
        for(int i=0;i<stones.size();i++){
            sum+=stones[i];
        }
        int target;
        target = sum/2;
        vector<int> dp(15005,0);//初始化
        //dp[j]的含义是在容量为j的背包中,取最大价值的石头
        for(int i=0;i<stones.size();i++){
            for(int j=target;j>=stones[i];j--){
                dp[j] = max(dp[j-stones[i]]+stones[i],dp[j]);//这里价值和重量相等
            }
        }
        int result = sum-dp[target]-dp[target];
        return result;
    }
};

Leetcode 494. 目标和

题目链接 494 目标和

本题目思路比较难想:

如何转化为01背包问题呢。

假设加法的总和为x,那么减法对应的总和就是sum - x。

所以我们要求的是 x - (sum - x) = target

x = (target + sum) / 2

此时问题就转化为,装满容量为x的背包,有几种方法

要注意dp的含义:dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法

自身感觉卡哥在视频中没讲清楚,看了一下别人的讲解觉得不错:

dp[j]=dp[j]+dp[j-nums[i]]

这个方程的意思是,如果我们要用若干个元素组成和为j的方案数,那么有两种选择:不选第i个元素或者选第i个元素。如果不选第i个元素,那么原来已经有多少种方案数就不变;如果选第i个元素,那么剩下要组成和为j - nums【i】 的方案数就等于dp[j - nums【i】]。所以两种选择相加就是dp【j】。

下面上代码:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum = 0;
        for(int i=0;i<nums.size();i++){
            sum+=nums[i];
        }
        //两种情况的特判
        if(abs(target)>sum){
            return 0;
        }
        //奇数不存在
        if((target+sum)%2 == 1){
            return 0;
        }
        
        int left = (target+sum)/2;
        vector<int> dp(left+1,0);
        dp[0] = 1;
        for(int i=0;i<nums.size();i++){
            for(int j=left;j>=nums[i];j--){
                //dp的含义是取j个元素能得到target的方案数
                dp[j]=dp[j]+dp[j-nums[i]];
            }
        }
        return dp[left];
    }
};

Leetcode 474. 一和零

题目链接 474 一和零

本题也是01背包,只不过是两个维度,就是一个三位数组,下面上代码:

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m+1,vector<int> (n+1,0));
        for(string str : strs){
            int z = 0;
        int y = 0;
        for(char c : str){//遍历物品
            if(c == '0'){
                z++;
            }else{
                y++;
            }
        }
        for(int i=m;i>=z;i--){//遍历容量
            for(int j=n;j>=y;j--){
                dp[i][j] = max(dp[i-z][j-y]+1,dp[i][j]);
            }
        }

        }
  return dp[m][n];      
    }
};

对于01背包又有点迷了,上课回来还要仔细思考一下

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值