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

简介: 【位运算 贪心】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⋯ \cdotsjm 中选择若干数,使得其和等于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

性质二

image.png

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


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

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。

相关文章
|
人工智能 机器人 Go
无需安装SD,QuickQR.Art艺术二维码保姆级教程!(营销新风口)
无需安装SD,QuickQR.Art艺术二维码保姆级教程!(营销新风口)
599 0
|
11月前
|
人工智能 IDE 程序员
GitHub Copilot 免费了!程序员们的福音来了!
《GitHub Copilot 免费了!程序员们的福音来了!》 近日,GitHub 宣布其 AI 编程助手 GitHub Copilot 现在可以免费使用。曾经每月需支付 10 美元订阅费的 Copilot,现在向所有人开放免费版本,这对个人开发者、初学者和小型团队来说是个大好消息。免费版支持 GPT 和 Claude 模型,并提供每月 2000 次代码补全和 50 条聊天消息等核心功能。用户只需注册或登录 GitHub 账户,在 VS Code 中安装扩展并激活免费版即可使用。此外,Visual Studio Code 也完全免费,进一步降低了开发门槛。 除了
12000 7
GitHub Copilot 免费了!程序员们的福音来了!
|
9月前
|
数据采集 机器学习/深度学习 人工智能
Sitcom-Crafter:动画师失业警告!AI黑科技自动生成3D角色动作,剧情脚本秒变动画
Sitcom-Crafter 是一款基于剧情驱动的 3D 动作生成系统,通过多模块协同工作,支持人类行走、场景交互和多人交互,适用于动画、游戏及虚拟现实等领域。
548 4
|
10月前
|
搜索推荐 算法 大数据
大数据无处不在:揭秘日常生活中的大数据魔力
大数据无处不在:揭秘日常生活中的大数据魔力
502 10
|
编译器 开发工具 C语言
解锁QtCreator跨界神技!Windows下轻松驾驭OpenCV动态库,让你的跨平台开发如虎添翼,秒变视觉编程大师!
【8月更文挑战第4天】QtCreator是一款强大的跨平台IDE,便于创建多平台应用。本教程教你如何在Windows环境下集成OpenCV库至Qt项目。首先,下载匹配MinGW的OpenCV预编译版并解压。接着,在QtCreator中新建或打开项目,并在.pro文件中添加OpenCV的头文件和库文件路径。确保编译器设置正确。随后编写测试代码,例如加载和显示图片,并进行编译运行。完成这些步骤后,你就能在QtCreator中利用OpenCV进行图像处理开发了。
699 6
|
C# Windows
WPF中如何使用HandyCotrol控件库
WPF中如何使用HandyCotrol控件库
667 1
|
弹性计算 运维 安全
无影云电脑_无影_桌面即服务DaaS_弹性计算-阿里云
什么是阿里云无影云电脑?无影云电脑(原云桌面)是一种快速构建、高效管理桌面办公环境,无影云电脑可用于远程办公、多分支机构、安全OA、短期使用、专业制图等使用场景,阿里云百科分享无影云桌面的详细介绍、租用价格、云电脑的优势、使用场景、网络架构、无影云电脑与云服务器的区别以及关于无影云电脑的常见问题解答FAQ
643 0
|
JavaScript 前端开发 Android开发
安卓自动化 | autox.js
安卓自动化 | autox.js
1529 8