【位运算 贪心】2835. 使子序列的和等于目标的最少操作次数

2024-04-16 07:36

本文主要是介绍【位运算 贪心】2835. 使子序列的和等于目标的最少操作次数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

算法可以发掘本质,如:
一,若干师傅和徒弟互有好感,有好感的师徒可以结对学习。师傅和徒弟都只能参加一个对子。如何让对子最多。
二,有无限多1X2和2X1的骨牌,某个棋盘若干格子坏了,如何在没有坏的格子放足够多骨牌。
三,某个单色图,1表示前前景,0表示后景色。每次操作可以将一个1,变成0。如何在最少得操作情况下,使得没有两个1相邻(四连通)。
四,若干路人,有些人是熟人,如何选出最多的人参加实验。为了避免熟人影响实验的效果,参加的人不能是熟人。
一二是二分图的最大匹配,三是二分图的最小点覆盖,四是二分图最大独立集。 而这三者是等效问题。

本文涉及知识点

位运算 贪心

LeetCode 2835. 使子序列的和等于目标的最少操作次数

给你一个下标从 0 开始的数组 nums ,它包含 非负 整数,且全部为 2 的幂,同时给你一个整数 target 。
一次操作中,你必须对数组做以下修改:
选择数组中一个元素 nums[i] ,满足 nums[i] > 1 。
将 nums[i] 从数组中删除。
在 nums 的 末尾 添加 两个 数,值都为 nums[i] / 2 。
你的目标是让 nums 的一个 子序列 的元素和等于 target ,请你返回达成这一目标的 最少操作次数 。如果无法得到这样的子序列,请你返回 -1 。

数组中一个 子序列 是通过删除原数组中一些元素,并且不改变剩余元素顺序得到的剩余数组。

示例 1:

输入:nums = [1,2,8], target = 7
输出:1
解释:第一次操作中,我们选择元素 nums[2] 。数组变为 nums = [1,2,4,4] 。
这时候,nums 包含子序列 [1,2,4] ,和为 7 。
无法通过更少的操作得到和为 7 的子序列。
示例 2:

输入:nums = [1,32,1,2], target = 12
输出:2
解释:第一次操作中,我们选择元素 nums[1] 。数组变为 nums = [1,1,2,16,16] 。
第二次操作中,我们选择元素 nums[3] 。数组变为 nums = [1,1,2,16,8,8] 。
这时候,nums 包含子序列 [1,1,2,8] ,和为 12 。
无法通过更少的操作得到和为 12 的子序列。
示例 3:

输入:nums = [1,32,1], target = 35
输出:-1
解释:无法得到和为 35 的子序列。

提示:

1 <= nums.length <= 1000
1 <= nums[i] <= 230
nums 只包含非负整数,且均为 2 的幂。
1 <= target < 231

位运算

target可以拆分成 2i1+2i2+ ⋯ \cdots + 2 in
性质一:如果2j1+2j2 … \dots +2jm >= 2i 且 j1到jm都小于等于i。
则一定可以从 j1,j2 ⋯ \cdots jm 中选择若干数,使得其和等于2i
证明
i = 0 时 。 20=20.
x>=1,如果i=x,性质一成立,则i=x+1,性质一也成立。
由于左式 >= 2x+1 > 2x 故左式可以抽取s = 2x
左式 - S >= 2x,故还可以抽取S2 = 2x
S+S2和在一起,就是2x+1
性质二
令集合 T = {2j1,2j2 ⋯ \cdots , 2jm} , T 中可能有重复的数据。
令集合S ={ 2i1,2i2+ ⋯ \cdots , 2in },其中i1<i2 < ⋯ \cdots in S的和等于target
∀ i ( i ∈ i 1 , i 2 , ⋯ , i n ) t a r g e t i = ∑ x < = 2 i , x ∈ S T i = ∑ x < = 2 i x , x ∈ T \forall i(i \in{i1,i2,\cdots,in}) \quad targeti = \sum_{x <= 2^i },x\in S \quad Ti=\sum_{x <= 2^i }x,x\in T i(ii1,i2,,in)targeti=x<=2ixSTi=x<=2ix,xT
如果Ti大于等于targeti ⟺ \iff 本题
情况一:target只有一项,就是性质一。
情况二:如果target有x项成立,则x+1项也成立。移除x项后,就成了性质一。

解法
通过i从低位到高位枚举target,其和记录到:iNeed。
cur = 1 << i 。
nums中小于等于cur的加到llHas中。
如果 llHas < iNeed, 则拆分nums中的最小元素next到cur,如果无元素可拆分,则返回-1。
拆分后:一个cur加到llHas, next/2 next/4 … \dots cur 加到setNum。

本解法用的多键集合,其实用大根堆 更简洁。

代码

核心代码

class Solution {
public:int minOperations(vector<int>& nums, int target) {std::multiset<int> setNum(nums.begin(), nums.end());int iRet = 0;long long llHas	= 0;int iNeed = 0;for (int i = 0; i <= 30; i++) {const int cur = 1 << i;while (setNum.size() && (*setNum.begin() <= cur)) {llHas += *setNum.begin();setNum.erase(setNum.begin());}if (cur & target) {iNeed += cur;}while (llHas < iNeed) {auto it = setNum.lower_bound(cur);if (setNum.end() == it) { return -1; }int next = *it;setNum.erase(it);				while (cur != next) {next /= 2;setNum.emplace(next);iRet++;}llHas += cur;}	}return iRet;}
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{	vector<int> nums; int target;{Solution sln;nums = { 1, 2, 8 }, target = 7;auto res = sln.minOperations(nums, target);Assert(1, res);}{Solution sln;nums = { 1, 32, 1, 2 }, target = 12;auto res = sln.minOperations(nums, target);Assert(2, res);}{Solution sln;nums = { 1,32,1 }, target = 35;auto res = sln.minOperations(nums, target);Assert(-1, res);}}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

这篇关于【位运算 贪心】2835. 使子序列的和等于目标的最少操作次数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/908169

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

Python使用openpyxl读取Excel的操作详解

《Python使用openpyxl读取Excel的操作详解》本文介绍了使用Python的openpyxl库进行Excel文件的创建、读写、数据操作、工作簿与工作表管理,包括创建工作簿、加载工作簿、操作... 目录1 概述1.1 图示1.2 安装第三方库2 工作簿 workbook2.1 创建:Workboo

Spring的RedisTemplate的json反序列泛型丢失问题解决

《Spring的RedisTemplate的json反序列泛型丢失问题解决》本文主要介绍了SpringRedisTemplate中使用JSON序列化时泛型信息丢失的问题及其提出三种解决方案,可以根据性... 目录背景解决方案方案一方案二方案三总结背景在使用RedisTemplate操作redis时我们针对

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配

JSONArray在Java中的应用操作实例

《JSONArray在Java中的应用操作实例》JSONArray是org.json库用于处理JSON数组的类,可将Java对象(Map/List)转换为JSON格式,提供增删改查等操作,适用于前后端... 目录1. jsONArray定义与功能1.1 JSONArray概念阐释1.1.1 什么是JSONA

Java操作Word文档的全面指南

《Java操作Word文档的全面指南》在Java开发中,操作Word文档是常见的业务需求,广泛应用于合同生成、报表输出、通知发布、法律文书生成、病历模板填写等场景,本文将全面介绍Java操作Word文... 目录简介段落页头与页脚页码表格图片批注文本框目录图表简介Word编程最重要的类是org.apach

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os