【位运算】【脑筋急转弯】2749. 得到整数零需要执行的最少操作数

简介: 【位运算】【脑筋急转弯】2749. 得到整数零需要执行的最少操作数

本文涉及知识点

2749. 得到整数零需要执行的最少操作数

给你两个整数:num1 和 num2 。

在一步操作中,你需要从范围 [0, 60] 中选出一个整数 i ,并从 num1 减去 2i + num2 。

请你计算,要想使 num1 等于 0 需要执行的最少操作数,并以整数形式返回。

如果无法使 num1 等于 0 ,返回 -1 。

示例 1:

输入:num1 = 3, num2 = -2

输出:3

解释:可以执行下述步骤使 3 等于 0 :

  • 选择 i = 2 ,并从 3 减去 22 + (-2) ,num1 = 3 - (4 + (-2)) = 1 。
  • 选择 i = 2 ,并从 1 减去 22 + (-2) ,num1 = 1 - (4 + (-2)) = -1 。
  • 选择 i = 0 ,并从 -1 减去 20 + (-2) ,num1 = (-1) - (1 + (-2)) = 0 。
    可以证明 3 是需要执行的最少操作数。
    示例 2:
    输入:num1 = 5, num2 = 7
    输出:-1
    解释:可以证明,执行操作无法使 5 等于 0 。
    提示:
    1 <= num1 <= 109
    -109 <= num2 <= 109

脑筋急转弯

特殊情况

num2为0,2x 能通过y次操作变成0,求y的取值范围。

x == 1时,只能i 取0,故y∈ \in[1,1]。

x == 2时,21,y == 1 ; 20+20,y==2,故y∈ \in[1,2]。

x == 4 时,y∈ \in [1,4] , 22 , 2 1 + 21 , 21+20+20 , 20+20+20+20

猜测:2m 可以通过[1,2m]操作变成0。

m = 0,只能取1。

证明: m >=0 , 2m的操作次数f(m)范围是[1,2m],则2m+1的操作次数范围是[1,2m+1]。

f(m+1)=f(m)+f(m) ,故f(m+1)∈ \in [2,2*2m]即[2,2m+1]。

直接减2m+1,操作次数就是1。故: f(m+1)∈ \in [1,2m+1]。

任意数都可以表示为:2m1+2m2 ⋯ \cdots 2mo

当num2为零时:num1的操作次数的合法范围是:[num1中1的位数,num1]。

分析

特殊情况无需排除:num1为0,结果为0。

令操作y1次后,还需要减去 num3 = num1 - num2*y1。如果y1 ∈ \in[num3中1的个数,num3] 则可以让结果为0。

num3必须大于等于0,这条无需额外判断,因为y1 必须小于等于num3。如果num3为0,这条不符合。

当y1等于64,一定大于num3中1的个数。如果y1 <= num3,则结果至少是64。如果此时无解,说明:64 > num3。

如果num2 >= 0,num不会变大,则num3永远不会变大,即永远不会大于y1。

如果num2 < 0,则num1取最小值0,num2取最大值-1,则nums3 = 64,和小于64矛盾。

当y1 <=64,则num3的取值范围:109*64 ,最多近40个二进制一。故只需要枚举y1∈ \in[0,40]。

代码

核心代码

class CBitCounts
{
public:
  CBitCounts(int iMaskCount)
  {
    for (int i = 0; i < iMaskCount; i++)
    {
      m_vCnt.emplace_back(bitcount(i));
    }
  }
  template<class T>
  static int bitcount(T x) {
    int countx = 0;
    while (x) {
      countx++;
      x &= (x - 1);
    }
    return countx;
  }
  vector<int> m_vCnt;
};
class Solution {
public:
  int makeTheIntegerZero(int num1, int num2) {
    for (long long i = 0; i < 61; i++)
    {
      const long long llNeed = num1 - num2 * i;
      const int iOneCnt = CBitCounts::bitcount((unsigned long long)llNeed);
      if ( (i  >= iOneCnt)&&(i <= llNeed))
      {
        return i;
      }
    }
    return -1;
  }
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& 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()
{
  int num1, num2;
  {
    Solution sln;
    num1 =3 ,num2 = -2 ;
    auto res = sln.makeTheIntegerZero(num1, num2);
    Assert(3, res);
  }
  {
    Solution sln;
    num1 = 5, num2 = 7;
    auto res = sln.makeTheIntegerZero(num1, num2);
    Assert(-1, res);
  }
}

2023年6月

class Solution {
public:
int makeTheIntegerZero(int num1, int num2) {
if (0 == num1)
{
return 0;
}
unsigned long long n = num1;
for (int i = 1; i <= 60; i++)
{
n -= num2;
if (n >= 0 && Is(n,i))
{
return i;
}
}
return -1;
}
bool Is(unsigned long long n, int iCi)
{
if (n >= ((long long)1 << 61))
{
return false;
}
long long iCanSub = bitcount(n);
if (iCanSub > iCi)
{
return false;
}
if (bitcount(n) == iCi)
{
return true;
}
for (int i = 1; i <= 60; i++)
{
if (n & (1LL << i))
{
iCanSub += (1LL << i) - 1;
}
}
return iCanSub >= iCi;
}
};


扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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++**实现。

相关文章
|
2月前
|
Java 开发者
【编程基础知识】2的n次幂与二进制位全为1之间的联系,为啥只差一个1
本文深入探讨了2的n次幂与二进制位全为1之间的数学联系,解释了2的n次幂减一的二进制表示为何全为1,并探讨了这一特性在HashMap中的应用。通过基础数学原理和实际代码示例,文章揭示了这一特性的实用价值,适合各水平的编程爱好者学习。
26 3
|
7月前
|
算法 测试技术 C#
【数学】【位运算】LeetCoce810. 黑板异或游戏
【数学】【位运算】LeetCoce810. 黑板异或游戏
|
7月前
|
存储 算法 搜索推荐
C语言第二十七练 异或的运算规律
C语言第二十七练 异或的运算规律
64 0
【每日挠头算法(4)】字符串相加|字符串相乘
【每日挠头算法(4)】字符串相加|字符串相乘
|
人工智能 算法 C++
【基础算法】关于高精度计算的问题【很高位数数据的加减乘除(相关代码用C++实现)】
【基础算法】关于高精度计算的问题【很高位数数据的加减乘除(相关代码用C++实现)】
|
存储 算法
【每日挠头算法题】Leetcode 989. 数组形式的整数加法 —— 高精度加法解法
【每日挠头算法题】Leetcode 989. 数组形式的整数加法 —— 高精度加法解法
148 0
【每日挠头算法题】Leetcode 989. 数组形式的整数加法 —— 高精度加法解法
【每日一题Day41】生成交替二进制字符串的最小操作数 | 模拟 位运算
思路:长度一定的交替二进制字符串有两种可能性,以字符0开头的0101字符串和以字符1开头的1010字符串,因此只需要将字符串s与这两种字符串进行比较,记录不相同的字符个数,最后返回较小值即可
101 0
【每日一题Day41】生成交替二进制字符串的最小操作数 | 模拟 位运算
|
C语言
下面【整型提升】的例题,你会几道?学完这一课,你将真正拿捏整型提升问题
下面【整型提升】的例题,你会几道?学完这一课,你将真正拿捏整型提升问题
150 0
下面【整型提升】的例题,你会几道?学完这一课,你将真正拿捏整型提升问题
|
存储
移位运算、位运算、逻辑运算相关知识点及笔试题
移位运算、位运算、逻辑运算相关知识点及笔试题
299 0
移位运算、位运算、逻辑运算相关知识点及笔试题
|
人工智能
刷爆力扣之数组形式的整数加法
刷爆力扣之数组形式的整数加法

热门文章

最新文章