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

news2025/2/25 11:20:56

最后一块石头重量Ⅱ

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

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

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

相关文章

鸿蒙OpenHarmony技术:【Docker编译环境】

Docker环境介绍 OpenHarmony为开发者提供了两种Docker环境&#xff0c;以帮助开发者快速完成复杂的开发环境准备工作。两种Docker环境及适用场景如下&#xff1a; 独立Docker环境&#xff1a;适用于直接基于Ubuntu、Windows操作系统平台进行版本编译的场景。基于HPM的Docker环…

企业合规视角下的菜鸟网络与拼多多不正当竞争案

近日&#xff0c;浙江省高院对备受瞩目的“菜鸟网络诉拼多多不正当竞争案”做出终审判决。该案件从2022年初发酵至今&#xff0c;终于以法院驳回拼多多上诉、维持一审判决而告一段落。此案不仅在法律层面引起广泛关注&#xff0c;更在企业合规方面提供了重要的案例参考。 根据判…

ESP32引脚入门指南(五):从理论到实践(SPI)

ESP32 微控制器因其丰富的外设接口而备受赞誉&#xff0c;其中SPI&#xff08;Serial Peripheral Interface&#xff09;是一种常见的通信协议。本文将深入探讨ESP32的SPI、HSPI&#xff08;High-Speed SPI&#xff09;和VSPI&#xff08;Very High-Speed SPI&#xff09;接口&…

Qt三方库:QuaZIP介绍、编译和使用

前言 Qt使用一些压缩解压功能&#xff0c;探讨过libzip库&#xff0c;zlib库&#xff0c;libzip库比较原始&#xff0c;还有其他库&#xff0c;都比较基础&#xff0c;而在基础库之上&#xff0c;又有高级封装库&#xff0c;Qt中的QuaZIP是一个很好的选择。Quazip是一个用于压缩…

如何防止WordPress网站内容被抓取

最近在检查网站服务器的访问日志的时候&#xff0c;发现了大量来自同一个IP地址的的请求&#xff0c;用站长工具分析确认了我的网站内容确实是被他人的网站抓取了&#xff0c;我第一时间联系了对方网站的服务器提供商投诉了该网站&#xff0c;要求对方停止侵权行为&#xff0c;…

5月白银现货最新行情走势

美联储5月的议息会议举行在即&#xff0c;但从联邦公开市场委员会&#xff08;FOMC&#xff09;近期透露的信息来看&#xff0c;降息似乎并没有迫切性。——美联储理事鲍曼认为通胀存在"上行风险"&#xff0c;明尼阿波利斯联邦储备银行行长卡什卡利提出了今年不降息的…

Python修改exe之类的游戏文件中的数值

文章目录 场景查找修改 补充字节to_bytes 场景 某些游戏数值&#xff08;攻击力、射程、速度…&#xff09;被写在exe之类的文件里 要先查找游戏数值&#xff0c;然后修改 查找 首先&#xff0c;要查找数值&#xff0c;大数重复较少&#xff0c;建议从大数找起 F 游戏原件…

AXI4写时序在AXI Block RAM (BRAM) IP核中的应用

在本文中将展示描述了AXI从设备&#xff08;slave&#xff09;AXI BRAM Controller IP核与Xilinx AXI Interconnect之间的写时序关系。 1 Single Write 图1是一个关于32位宽度的BRAM&#xff08;Block RAM&#xff09;的单次写入操作的例子。这个例子展示了如何向地址0x1000h…

45.乐理基础-音符的组合方式-复附点

复附点&#xff1a; 复附点顾名思义就是两个附点 复附点表示的音符&#xff0c;有多少拍&#xff1f;下面拿 复附点四分音符举例&#xff0c;可以把整个音符看成三部分&#xff0c;第一部分是原本的四分音符&#xff0c;第二部分是第一个附点&#xff0c;第三部分是第二个附点&…

C++动态内存管理:与C语言动态内存管理的差异之争

当你改错一行代码的时候&#xff1a; 当你想要重构别人的代码时&#xff1a; 目录 前言 一、C/C的内存分布 二、C/C语言中的动态内存管理 三、new与delete的实现原理 总结&#xff1a; 前言 在C中&#xff0c;内存管理是一个至关重要的主题。正确地管理内存可以避免内存泄…

数字工厂管理系统如何助力企业数据采集与分析

随着科技的不断进步&#xff0c;数字化已成为企业发展的重要趋势。在制造业领域&#xff0c;数字工厂管理系统的应用日益广泛&#xff0c;它不仅提升了生产效率&#xff0c;更在数据采集与分析方面发挥着举足轻重的作用。本文旨在探讨数字工厂管理系统如何助力企业数据采集与分…

H5 处理点击元素高亮、自定义按钮、去除焦点边框

1、设置移动设备上点击元素时出现的高亮颜色 *{-webkit-tap-highlight-color: transparent; }2、如果你想要自定义按钮的样式&#xff0c;你可以使用 -webkit-appearance: none; 来移除按钮的默认样式 .button {-webkit-appearance: none;appearance: none; /* 兼容性更好的通…

【学习AI-相关路程-工具使用-自我学习-Ubuntucudavisco-开发工具尝试-基础样例 (2)】

【学习AI-相关路程-工具使用-自我学习-cuda&visco-开发工具尝试-基础样例 &#xff08;2&#xff09;】 1、前言2、环境说明3、总结说明4、工具安装0、验证cuda1、软件下载2、插件安装 5、软件设置与编程练习1、创建目录2、编译软件进入目录&创建两个文件3、编写配置文…

FinalShell连接虚拟机Linux系统连接超时

报错信息 java.net.ConnectException: Connection timed out: connect 排除是网络问题后可以尝试一下这个方法。 解决方案: 打开虚拟机终端输入:ifconfig 会出现端口信息: 看ens33这里的端口是多少&#xff0c;改一下重新连接就ok。

java spring 10 Bean的销毁过程 上 在docreatebean中登记要销毁的bean

1.Bean销毁是发送在Spring容器关闭过程中的 AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);UserService userService (UserService) context.getBean("userService");userService.test();// 容器关闭cont…

Java找不到包解决方案

在跟着教程写Spingboot后端项目时&#xff0c;为了加快效率&#xff0c;有时候有的实体文件可以直接粘贴到目录中&#xff0c;此时运行项目会出现Java找不到包的情况&#xff0c;即无法找到导入的实体文件&#xff0c;这是项目没有更新的原因。解决方法&#xff1a; 刷新Maven:…

如何在40分钟之内,又快又准完成四六级阅读柯桥考级英语培训

答题步骤和技巧 1 选词填空 选词填空部分字数在200~300之间&#xff0c;设有10个空&#xff0c;提供15个备选项&#xff0c;从中选出最合适答案。选词填空题相对于普通的完型题简单&#xff0c;但是考察内容基本一致。集中考察的点有语法现象&#xff0c;逻辑衔接和搭配。每空…

纯血鸿蒙APP实战开发——数字滚动动效实现

介绍 本示例主要介绍了数字滚动动效的实现方案。 该方案多用于数字刷新&#xff0c;例如页面刷新抢票数量等场景。 效果图预览 使用说明&#xff1a; 下拉页面刷新&#xff0c;数字进行刷新。 实现思路 通过双重ForEach循环分别横向、纵向渲染数字。 Row() {ForEach(this…

Golang面向对象编程(一)

文章目录 结构体基本介绍结构体定义方式创建结构体变量结构体内存对齐结构体类型转换字段的Tag标签 方法基本介绍方法的定义和调用方法调用的传参机制String方法 结构体 基本介绍 基本介绍 Go支持面向对象编程特性&#xff0c;包括封装、继承和多态&#xff0c;但Go中没有类&a…

Day 29 MySQL的主从复制集群

一&#xff1a;主从复制 1.主从复制概念 什么是主从复制&#xff1a; ​ 主从复制&#xff0c;是用来建立一个和主数据库完全一样的数据库环境&#xff0c;称为从数据库&#xff1b;主数据库一般是准实时的业务数据库 主从复制的作用&#xff1a; ​ 做数据的热备&#xf…