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

最后一块石头重量Ⅱ

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

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 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

​ 关键点在想到:让石头尽量分成重量相同的两堆,相撞之后剩下的石头最小

​ 又因为唯一性,很自然就化解为了01背包问题;

​ 本题物品的重量为stones[i],物品的价值也为stones[i]。

​ 对应着01背包里的物品重量weight[i]和 物品价值value[i]。

​ 动规五部曲:
​ 1.dp数组含义:
​ dp[j]表示容量为j的背包,最多可以背的最大重量为dp[j];

​ 2.确定递推公式:

​ dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);

​ 3.初始化:

​ 因为提示中给出1 <= stones.length <= 30,1 <= stones[i] <= 1000,所以最大重量就是30 * 1000 。

​ 而我们要求的target其实只是最大重量的一半,所以dp数组开到15000大小就可以了。

​ 当然也可以把石头遍历一遍,计算出石头总重量 然后除2,得到dp数组的大小。

​ 我这里就直接用15000了。

​ 即vector<int> dp (15001, 0);

​ 4.遍历顺序:

​ 和之前的一致,内层倒序:

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]);}
}

​ 5.打印数组:

#include<iostream>
#include<vector>
#include<numeric>
using namespace std;
class solution {
public:int lastStoneWeightII(vector<int>& stones){int sum = accumulate(stones.begin(), stones.end(), 0);//向下取整求背包的最大空间int target = sum / 2;vector<int> dp(15001, 0);//根据测试案例调整dp数组大小for (int i = 0; i < stones.size(); i++) {cout << "The current dp array is:" << endl;for (int j = target; j >= stones[i]; j--) {dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);}for (int k = 0; k <= target; k++) {cout << dp[k] << ' ';}cout << endl;}return sum - 2 * dp[target];}
};
int main() {solution mySolution;vector<int> tests = { 2,4,1,1 };cout << "The result is:" << mySolution.lastStoneWeightII(tests) << endl;return 0;
}

目标和

给定一个非负整数数组,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 = sum_plus - sum_minus其中,sum_plus + sum_minus = sum;

​ 所以sum_minus = (sum - target)/2;

​ 找这个sum_minus是否存在即可

​ 动规五部曲:

​ 1.dp数组及其下标含义:

​ dp[j]表示sum_minus为j时有dp[j]种方法使得子集和为sum_minus;

​ 2.确认递推公式:

​ 这里借用二维数组来方便理解:

​ dp[i][j] = dp[i-1][j] + dp[i-1][j -nums[i]];

​ dp[i - 1][j]是不将物品i放入背包的方式数,dp[i-1][j - nums[i]]使将物品i放入背包的方式数;

​ 再次确定此时一维dp数组含义,dp[j]指的是子集和为j的情况下的路径数:

​ 要用若干个元素组成和为j的方案数,那么有两种选择:不选第i个元素或者选第i个元素;

​ 如果不选第i个元素,那么原来已经有多少种方案数就不变;

​ 如果选第i个元素,那么就是在已有的基础上,加上剩下要组成和为j - nums[i] 的方案数就等于dp[j - nums[i]];

​ 所以,很显然,dp[j] = dp[j] + dp[j - nums[i]];

​ 3.初始化:

​ 很显然,根据上面的推导,dp[0] = 1,不然的话所有项都是0,其余dp[j] = 0;

​ 4.遍历顺序:

​ 经典一维01背包

​ 5.打印数组:
image-20240510200606342

image-20240510203829314

#include<numeric>
#include<iostream>
#include<vector>using namespace std;class solution {
public:int findTargetSumWays(vector<int>& nums, int target) {int sum = accumulate(nums.begin(), nums.end(), 0);if (abs(target) > sum)	return 0;if ((sum -  target) % 2 == 1)	return 0;int sum_minus = (sum - target) / 2;vector<int> dp(1001, 0);//因为初始数组和小于1000,target可取范围为-1000-1000,所以sum_minus <= 1000恒成立dp[0] = 1;for (int i = 0; i < nums.size(); i++) {for (int j = sum_minus; j >= nums[i]; j--) {dp[j] += dp[j - nums[i]];}cout << "The current dp array will be shown as below:" << endl;for (int k = 0; k <= sum_minus; k++) {cout << dp[k] << ' ';}cout << endl;}return dp[sum_minus];}
};int main() {cout << "Please enter the test sequences(requiring non-negative integers) end with -1:" << endl;vector<int> tests;int num;while (cin >> num && num != -1) {tests.push_back(num); // 将输入的整数添加到vector中  }cout << "Please enter the target sum:" << endl;int target;cin >> target;solution mySolution;cout << "There are " << mySolution.findTargetSumWays(tests, target) << " ways to get to the target sum." << endl;return 0;
}

一和零

给你一个二进制字符串数组 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

​ 看起来好像很复杂,实际上就是拥有两个维度的背包,容量分别为m和n;

​ 至于strs虽然看上去有许多重复的0 1,但是实际上每个strs[i]只能取一次,所以还是0-1背包问题;

​ 动规五部曲:
​ 1.dp数组含义及其下标:

​ dp[i][j],表示在子集在最多有m个0,n个1的前提下,最多可以选择有dp[i][j]个元素;

​ 2.递推公式:

​ 先考虑最原始的0-1背包问题:

​ dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + values[i]);

​ 对于本题:

​ dp[i][j] = max(dp[i][j], dp[i - zero_nums][y - one_nums] +1);

​ 3.初始化:
​ 很显然,此时的dp[0][0] = 0;

​ 又因为递推公式是需要比较最大值的,所以所有dp[i][j] = 0;

​ 4.遍历顺序:

​ 经典倒序:

		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);}}}

​ 5.打印dp数组:
在这里插入图片描述

#include<iostream>
#include<string>
#include<vector>
using namespace std;
class solution {
public:int findMaxFormvector(vector<string>& strs, int m, int n) {vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));//dp数组初始化for (vector<string>::size_type i = 0; i < strs.size(); i++) {string str = strs[i];int zero_nums = 0, one_nums = 0;for (string::size_type j = 0; j < str.size(); j++) {char c = str[j];if (c == '1')	one_nums++;else zero_nums++;}for (int i = m; i >= zero_nums; i--) {for (int j = n; j >= one_nums; j--) {dp[i][j] = max(dp[i][j], dp[i - zero_nums][j - one_nums] + 1);}}cout << "The current dp array will be shown as below:" << endl;for (int i = 0; i <= m; i++) {for (int j = 0; j <= n; j++) {cout << dp[i][j] << ' ';}cout << endl;}}return dp[m][n];}
};int main() {cout << "Please enter the strings(only 0 and 1 are allowed),seperated by enter,quit with\"stop\"" << endl;solution ms;vector<string> strs;string input;while (true) {getline(cin, input);if (input == "stop")	break;strs.push_back(input);}cout << "Please enter the maximum '0' numbers and '1' numbers:" << endl;int m, n;cin >> m >> n;cout << "The maximum subset's elements is: " << ms.findMaxFormvector(strs, m, n) << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/9755.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Transformers中加载预训练模型的过程剖析

使用HuggingFace的Transformers库加载预训练模型来处理下游深度学习任务很是方便,然而加载预训练模型的方法多种多样且过程比较隐蔽,这在一定程度上会给人带来困惑。因此,本篇文章主要讲一下使用不同方法加载本地预训练模型的区别、加载预训练模型及其配置的过程,藉此做个记…

【go项目01_学习记录10】

操作数据库 1 插入数据2 显示文章2.1 修改 articlesShowHandler() 函数2.2 代码解析 3 编辑文章3.1 添加路由3.2 编辑articlesEditHandler()3.3 新建 edit 模板3.4 代码重构3.5 完善articlesUpdateHandler()3.6 测试更新3.7 封装表单验证 1 插入数据 . . . func articlesStore…

厚德提问大佬答4:AI绘画生成的心得

遇到难题不要怕&#xff01;厚德提问大佬答&#xff01; 厚德提问大佬答 你是否对AI绘画感兴趣却无从下手&#xff1f;是否有很多疑问却苦于没有大佬解答带你飞&#xff1f;从此刻开始这些问题都将迎刃而解&#xff01;你感兴趣的话题&#xff0c;厚德云替你问&#xff0c;你解…

车载电子电器架构 —— 应用软件开发(中)

车载电子电器架构 —— 应用软件开发(中) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…

算法设计课第五周(贪心法实现活动选择问题)

目录 一、【实验目的】 二、【实验内容】 三、实验源代码 一、【实验目的】 &#xff08;1&#xff09;熟悉贪心法的设计思想 &#xff08;2&#xff09;理解贪心法的最优解与正确性证明之间的关系 &#xff08;3&#xff09;比较活动选择的各种“贪心”策略&#xff0c;…

动态IP避坑指南:如何挑选合适的动态代理IP?

在如今的网络环境中&#xff0c;使用动态IP代理成为实现隐私保护、访问受限内容和提高网络效率的一种常见方式&#xff0c;选择合适的国外动态IP代理可以让我们的业务处理事半功倍。面对市面上琳琅满目的选择&#xff0c;如何挑选购买适合自己的动态IP代理服务呢&#xff1f;在…

【数据结构】手把手带你玩转线性表

前言&#xff1a; 哈喽大家好&#xff0c;我是野生的编程萌新&#xff0c;首先感谢大家的观看。数据结构的学习者大多有这样的想法&#xff1a;数据结构很重要&#xff0c;一定要学好&#xff0c;但数据结构比较抽象&#xff0c;有些算法理解起来很困难&#xff0c;学的很累。我…

弱监督语义分割-对CAM的生成过程进行改进1

一、仿射变换图像结合正则项优化CAM生成 论文&#xff1a;Self-supervised Equivariant Attention Mechanism for Weakly Supervised Semantic Segmentation &#xff08;CVPR,2020&#xff09; 1.SEAM方法 孪生网络架构&#xff08;Siamese Network Architecture&#xff09…

2024.5.10

TCP服务器端 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//设置窗口大小和窗口大小固定this->resize(727,879);this->setFixedSize(727,879);//创建…

STC8增强型单片机开发【定时器Timer⭐】

目录 一、引言 二、定时器基础知识 三、STC8定时器配置 四、代码示例 五、总结 一、引言 在单片机开发中&#xff0c;定时器&#xff08;Timer&#xff09;是一个极其重要的组件&#xff0c;它允许开发者基于时间触发各种事件或任务。STC8增强型单片机作为一款功能丰富的…

使用2G内存求20亿个数字中出现次数最多的N个

又是一个TOP -N的题目 我看了一下CSDN上大多数人的回答和GPT说的差不多&#xff0c;都是说使用哈希之类的&#xff1b; 我今天说一下我的解法&#xff0c;首先说一下不太快的基础解法 20亿数字使用uint32需要80GB&#xff0c; &#xff08;1&#xff09;分为40块读取&#…

c++opencv Project3 - License Plate Detector

俄罗斯车牌识别案例&#xff1a;实时识别车牌&#xff0c;并且读取到指定文件夹中。 惯例先展示结果图&#xff1a; 对于摄像头读取图片进行车牌匹配&#xff0c;原理和人脸识别其实是一致的。 利用训练好的模型进行匹配即可。可参考&#xff1a; 对视频实现人脸识别-CSDN博…

电能表远程抄表系统是什么?

电能表远程抄表系统是一种优秀的电力管理方法&#xff0c;它通过自动化的形式搜集、解决与分析电能表的信息&#xff0c;进而取代了传统人工抄水表方法。其主要原理是运用物联网技术、通讯技术和大数据处理技术&#xff0c;完成对电度表数据信息实时、远程控制获取和管理方法。…

探索无界知识:用 ChatGPT 的原理学习任何事物!

为避免文章重复&#xff0c;您的文本已通过更改句式、用词以及句子结构进行了修改。现在的文本应该能更好地满足去重的需求&#xff1a; 从ChatGPT原理出发&#xff0c;我们探讨GPT如何启发人类学习和构建个人知识体系。 1. 明确学习目标 机器学习必须依靠目标函数。同样&…

【Qt 开发基础体系】QMap 类和 QHash 类以及 QVector 类

文章目录 1.QMap 详解1.1 QMap 的介绍1.2 QMap 的具体用法如下1.3 QmultiMap类 2.QHash 详解3. QMap 和 QHash 的对比4. QVector 详解 1.QMap 详解 1.1 QMap 的介绍 &#x1f427;① QMap<key,T>提供一个从类型为Key的键到类型为T的值的映射。通常&#xff0c;QMap存储的…

STC8增强型单片机开发【串口调试UART⭐⭐】

目录 一、引言 二、UART基础知识 三、STC8 UART配置 四、代码示例 上列代码中所需的库函数文件&#xff1a; 引入库函数的流程&#xff1a; 五、总结 一、引言 在单片机开发中&#xff0c;串口调试&#xff08;UART&#xff09;是一种常用的通信方式&#xff0c;用于实现…

linux grep命令搜索指定路径

在Linux开发的过程中grep这个搜索命令&#xff0c;是必不可少的存在。它可以快速的搜索出来我们需要的关键字所在的位置。 有助于我们快速分析定位问题。 下面&#xff0c;分享一个简单实用的小技巧。 原始grep 最终grep grep过滤掉二进制的文件 -I选项 结论 这样子是不…

126.删除链表的倒数第N个节点(力扣)

题目描述 代码解决&#xff08;双指针&#xff09; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, Li…

全视通助力珠海市井岸镇卫生院新院,建设智慧病房

5月6日&#xff0c;位于珠海市斗门区的井岸镇卫生院新院正式启用&#xff0c;面向市民开诊。新院各诊区就医秩序井然&#xff0c;总体情况良好。据统计&#xff0c;截至开诊当天11点30分&#xff0c;新院门诊共接诊347人次&#xff0c;预防接种81人次&#xff0c;儿童体检33人次…

网络相关笔记

IPv4地址 IPv4地址通常以“点分十进制”形式书写&#xff0c;即四个0-255之间的十进制数&#xff0c;各数之间用英文句点&#xff08;.&#xff09;分隔&#xff0c;例如&#xff1a;192.0.2.1。总共32位的地址空间可以表示大约42亿个不同的地址。 IPv4地址结构包括&#xff…