首页 > 编程语言 >算法学习Day43最后石头的重量、目标和、一和零

算法学习Day43最后石头的重量、目标和、一和零

时间:2024-01-31 09:44:57浏览次数:47  
标签:nums int 重量 strs 算法 子集 Day43 sum dp

Day43最后石头的重量、目标和、一和零

By HQWQF 2024/01/31

笔记


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

有一堆石头,每块石头的重量都是正整数。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎;

如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。

最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回 0。

示例:

  • 输入:[2,7,4,1,8,1]
  • 输出:1

解释:

  • 组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
  • 组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
  • 组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
  • 组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。

提示:

  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 1000

动态规划

只要我们尽量把让石头分成重量相同的两堆,这样相撞之后剩下的石头就会最小。

得出容量为sum/2的背包能装下的石头的最大总重量后,让Sum减去这个总重量的两倍就行。

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        vector<int> dp(15001, 0);
        int sum = 0;
        for (int i = 0; i < stones.size(); i++) sum += stones[i];
        int target = sum / 2;
        for (int i = 0; i < stones.size(); i++) { // 遍历物品
            for (int j = target; j >= stones[i]; j--) { // 遍历背包
                dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);
            }
        }
        return sum - dp[target] - dp[target];
    }
};

494.目标和

给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。

返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

示例:

  • 输入:nums: [1, 1, 1, 1, 1], S: 3
  • 输出:5

解释:

  • -1+1+1+1+1 = 3
  • +1-1+1+1+1 = 3
  • +1+1-1+1+1 = 3
  • +1+1+1-1+1 = 3
  • +1+1+1+1-1 = 3

一共有5种方法让最终目标和为3。

提示:

  • 数组非空,且长度不会超过 20 。
  • 初始的数组的和不会超过 1000 。
  • 保证返回的最终结果能被 32 位整数存下。

动态规划

若要让表达式结果为target,表达式中的一部分元素的符号需要是+一部分是-,设符号为+的部分元素的和为left,符号为-的部分元素的和为right,那么有 left - right = target。

同时我们有left + right = sum,解方程可得 left = (target + sum)/2 。要求添加符号的方法数就是求left 的组合,即问题转化为了在数组中找元素组合为(target + sum)/2 ,求组合的数量。

首先如果(target + sum) / 2 不为整说明没有组合,直接返回0。

先设一维dp表,dp[j]代表填满j(包括j)这么大容积的包,有dp[j]种方法

和前面一样,我们需要先遍历所有元素(遍历每行),每一行都代表使用num[0]、num[1]、……num[i],这些元素。对于每一行的dp[j],相比上一行,我们多了nums[i]可以使用,如果不使用nums[i]就和之前的组合重复所以不考虑。如果使用了nums[i],那么dp[j] (新使用nums[i])就等于未使用nums[i]凑到j - nums[i]的方法数,也就是上一行(上一迭代)的dp[j - nums[i]],考虑使用所有nums元素的情况,把这些dp[j](新使用num某个元素)累加就是dp[j]。

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

例如:dp[j],j 为5,

  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 容量为5的背包。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 容量为5的背包。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 容量为5的背包
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 容量为5的背包
  • 已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 容量为5的背包

初始化方面dp[0] = 1;其余为0。

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) sum += nums[i];
        if (abs(S) > sum) return 0; // 此时没有方案
        if ((S + sum) % 2 == 1) return 0; // 此时没有方案
        int bagSize = (S + sum) / 2;
        vector<int> dp(bagSize + 1, 0);
        dp[0] = 1;
        for (int i = 0; i < nums.size(); i++) {
            for (int j = bagSize; j >= nums[i]; j--) {
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[bagSize];
    }
};

474.一和零

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

示例 1:

  • 输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
  • 输出:4
  • 解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。 其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

示例 2:

  • 输入:strs = ["10", "0", "1"], m = 1, n = 1
  • 输出:2
  • 解释:最大的子集是 {"0", "1"} ,所以答案是 2 。

提示:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i] 仅由 '0' 和 '1' 组成
  • 1 <= m, n <= 100

动态规划

dp表为二维,dp[i][j]代表最多有i个0和j个1的(strs子集)的最大大小为dp[i][j]。

dp表为滚动,遍历每一个元素都遍历一遍dp表,逐步更新dp[i][j]的最大值,所以注意从后往前遍历。

zeroNum和oneNum是strs的一个元素中的0和1的数量。

递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);

如果最多有i个0和j个1的(strs子集)有当前元素的话更加大,那么这个更大的子集去掉这个元素后的(strs子集)也一定是(最多有i - zeroNum个0和j - oneNum个1)的(strs子集)中最大的,这个去掉后的子集大小加1也就是当前元素就等于在这个假设下的更大的子集的大小。

初始值方面,在只有一个元素的时候,没有这个元素的子集大小为0,所以全部初始为0。

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0)); // 默认初始化0
        for (string str : strs) { // 遍历物品
            int oneNum = 0, zeroNum = 0;
            for (char c : str) {
                if (c == '0') zeroNum++;
                else oneNum++;
            }
            for (int i = m; i >= zeroNum; i--) { // 遍历背包容量且从后向前遍历!
                for (int j = n; j >= oneNum; j--) {
                    dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
                }
            }
        }
        return dp[m][n];
    }
};

标签:nums,int,重量,strs,算法,子集,Day43,sum,dp
From: https://www.cnblogs.com/HQWQF/p/17998578

相关文章

  • 【学习笔记】根号算法
    1.分块【模板】线段树1我们把整个序列割成\(s\)个块,则块长为\(\frac{n}{s}\),对于一个跨越区间\([l,r]\)的修改/询问,很容易看出它最多包含两个散块,然后中间有一堆整块。考虑对于整块我们类似线段树的维护方法打tag,然后对于散块直接暴力。分析复杂度,最多有\(s\)个块,散......
  • 代码随想录算法训练营第三天 |203.移除链表元素 , 707.设计链表,206.反转链表
    206.反转链表 已解答简单 相关标签相关企业 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例1:输入:head=[1,2,3,4,5]输出:[5,4,3,2,1]示例2:输入:head=[1,2]输出:[2,1]示例3:输入:head=[]输出:[] 提示:链......
  • 代码随想录算法训练营第七天| 454.四数相加II 383. 赎金信 15. 三数之和 18. 四
    454.四数相加II 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i,j,k,l) 能满足:0<=i,j,k,l<nnums1[i]+nums2[j]+nums3[k]+nums4[l]==0题目链接:454.四数相加II-力扣(LeetCode)思路:当遇到需要确认元素是......
  • 类欧几里得算法
    模板题:P5170【模板】类欧几里得算法复述题解:我们记\(f(a,b,c,n)=\sum\limits_{i=0}^{n}\Big\lfloor\dfrac{ai+b}{c}\Big\rfloor\,,\g(a,b,c,n)=\sum\limits_{i=0}^{n}i\Big\lfloor\dfrac{ai+b}{c}\Big\rfloor\,,\h(a,b,c,n)=\sum\limits_{i=0}^{n}{\Big\lfloor......
  • PBKDF2算法:保护密码安全的重要工具
    摘要:在当今的数字世界中,密码安全是至关重要的。为了保护用户密码免受未经授权的访问和破解,Password-BasedKeyDerivationFunction2(PBKDF2)算法成为了一种重要的工具。本文将介绍PBKDF2算法的优缺点,以及它如何解决密码存储和验证中的一些问题。我们还将提供一个使用Java编......
  • 【机器学习】常见算法详解第2篇:KNN之kd树介绍(已分享,附代码)
    本系列文章md笔记(已分享)主要讨论机器学习算法相关知识。机器学习算法文章笔记以算法、案例为驱动的学习,伴随浅显易懂的数学知识,让大家掌握机器学习常见算法原理,应用Scikit-learn实现机器学习算法的应用,结合场景解决实际问题。包括K-近邻算法,线性回归,逻辑回归,决策树算法,集成学习,聚......
  • 白话机器学习算法入门笔记
    机器学习中常见的十大算法包括:1.线性回归(LinearRegression)-用于预测连续值的简单线性回归模型。2.逻辑回归(LogisticRegression)-用于分类问题的logistic回归模型。3.决策树(DecisionTree)-一种流行的树形分类与回归方法。4.支持向量机(SVM)-一种二分类模型,Fi......
  • 代码随想录算法训练营第六天 |242. 有效的字母异位词 349. 两个数组的交集 202. 快乐
    1.两数之和 已解答简单 相关标签相关企业 提示 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同......
  • 基于注意力机制与改进TF-IDF的推荐算法
    前言本篇文章是2020年8月发表于《计算机工程》的一篇期刊论文,文章名称《基于注意力机制与改进TF-IDF的推荐算法》。文章针对传统推荐系统主要依赖用户对物品的评分数据而无法学习到用户和项目的深层次特征的问题,提出基于注意力机制与改进TF-IDF的推荐算法(AMITI)。将双层注意力......
  • 算法模板 v1.5.1.20240130
    算法模板v1.1.1.20240115:之前的历史版本已经不可寻,创建了第一份算法模板。v1.2.1.20240116:删除“编译”-“手动开栈”与“编译”-“手动开O优化”;将“编译”-“CF模板”中的第20行代码cin>>T;注释;删除“读写”及其目录下的内容;删除“图论”-“欧拉图”-“混合图”;删除“图论”-......