作者推荐
视频算法专题
本文涉及知识点
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++**实现。