Skip to content

Commit fcb4db9

Browse files
authored
update: 添加问题“2749.得到整数零需要执行的最少操作数”的代码和题解 (#1116)
* 2749: WA.cpp (#1115) * 2749: WA.cpp (#1115) * 2749: AC.cpp (#1115) - AC,100.00%,87.50% * docs(2749): WA.cpp (#1115) * docs(2749): WA.cpp (#1115) * 2749: WA.cpp (#1115) - 469 / 542 个通过的测试用例 input: 16 10 should: -1 output: 59 * 2749: dbg.cpp (#1115) * update: 添加问题“2749.得到整数零需要执行的最少操作数”的代码和题解 (#1116) Signed-off-by: LetMeFly666 <[email protected]> * 2749: declaration.cpp (#1115) --------- Signed-off-by: LetMeFly666 <[email protected]>
1 parent 0b7992d commit fcb4db9

File tree

4 files changed

+234
-0
lines changed

4 files changed

+234
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* @Author: LetMeFly
3+
* @Date: 2025-09-05 18:29:32
4+
* @LastEditors: LetMeFly.xyz
5+
* @LastEditTime: 2025-09-05 23:57:58
6+
*/
7+
#if defined(_WIN32) || defined(__APPLE__)
8+
#include "_[1,2]toVector.h"
9+
#endif
10+
11+
/*
12+
nums1 - k * nums2 = 2^{i_1} + 2^{i_2} + ... + 2^{i_k}
13+
*/
14+
class Solution {
15+
public:
16+
int makeTheIntegerZero(int num1, int num2) {
17+
for (int k = 1; k <= num1 - (long long)num2 * k; k++) {
18+
if (k >= __builtin_popcountll(num1 - (long long)num2 * k)) {
19+
return k;
20+
}
21+
}
22+
return -1;
23+
}
24+
};
25+
26+
#if defined(_WIN32) || defined(__APPLE__)
27+
/*
28+
16 10
29+
30+
*/
31+
int main() {
32+
int a, b;
33+
while (cin >> a >> b) {
34+
Solution sol;
35+
cout << sol.makeTheIntegerZero(a, b) << endl;
36+
}
37+
return 0;
38+
}
39+
#endif
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* @Author: LetMeFly
3+
* @Date: 2025-09-05 23:51:34
4+
* @LastEditors: LetMeFly.xyz
5+
* @LastEditTime: 2025-09-06 00:13:36
6+
*/
7+
#if defined(_WIN32) || defined(__APPLE__)
8+
#include "_[1,2]toVector.h"
9+
#endif
10+
11+
// **** 这段代码不能通过这道题,但是它的错误样例能帮你更好地理解正确代码
12+
13+
/*
14+
nums1 - k * nums2 = 2^{i_1} + 2^{i_2} + ... + 2^{i_k}
15+
*/
16+
class Solution {
17+
public:
18+
int makeTheIntegerZero(int num1, int num2) {
19+
if (num1 - num2 < 1) {
20+
return -1;
21+
}
22+
int k = 0;
23+
while (++k) {
24+
if (k >= __builtin_popcountll(num1 - (long long)num2 * k)) {
25+
return k;
26+
}
27+
}
28+
return -2; // Fake Return: unreachable
29+
}
30+
};
31+
32+
// 这样写的错因在于没有限制上界
33+
// 16 10会在k=2时不满足上界而退出

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,7 @@
869869
|2741.特别的排列|中等|<a href="https://leetcode.cn/problems/special-permutations/" target="_blank">题目地址</a>|<a href="https://blog.letmefly.xyz/2024/06/26/LeetCode%202741.%E7%89%B9%E5%88%AB%E7%9A%84%E6%8E%92%E5%88%97/" target="_blank">题解地址</a>|<a href="https://letmefly.blog.csdn.net/article/details/140000372" target="_blank">CSDN题解</a>|<a href="https://leetcode.cn/problems/special-permutations/solutions/2823238/letmefly-2741te-bie-de-pai-lie-zhuang-ya-qs1k/" target="_blank">LeetCode题解</a>|
870870
|2744.最大字符串配对数目|简单|<a href="https://leetcode.cn/problems/find-maximum-number-of-string-pairs/" target="_blank">题目地址</a>|<a href="https://blog.letmefly.xyz/2024/01/17/LeetCode%202744.%E6%9C%80%E5%A4%A7%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%85%8D%E5%AF%B9%E6%95%B0%E7%9B%AE/" target="_blank">题解地址</a>|<a href="https://letmefly.blog.csdn.net/article/details/135662583" target="_blank">CSDN题解</a>|<a href="https://leetcode.cn/problems/find-maximum-number-of-string-pairs/solutions/2608691/letmefly-2744zui-da-zi-fu-chuan-pei-dui-lnd3n/" target="_blank">LeetCode题解</a>|
871871
|2748.美丽下标对的数目|简单|<a href="https://leetcode.cn/problems/number-of-beautiful-pairs/" target="_blank">题目地址</a>|<a href="https://blog.letmefly.xyz/2024/06/20/LeetCode%202748.%E7%BE%8E%E4%B8%BD%E4%B8%8B%E6%A0%87%E5%AF%B9%E7%9A%84%E6%95%B0%E7%9B%AE/" target="_blank">题解地址</a>|<a href="https://letmefly.blog.csdn.net/article/details/139842524" target="_blank">CSDN题解</a>|<a href="https://leetcode.cn/problems/number-of-beautiful-pairs/solutions/2816858/2748mei-li-xia-biao-dui-de-shu-mu-mo-ni-c3paz/" target="_blank">LeetCode题解</a>|
872+
|2749.得到整数零需要执行的最少操作数|中等|<a href="https://leetcode.cn/problems/minimum-operations-to-make-the-integer-zero/" target="_blank">题目地址</a>|<a href="https://blog.letmefly.xyz/2025/09/05/LeetCode%202749.%E5%BE%97%E5%88%B0%E6%95%B4%E6%95%B0%E9%9B%B6%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84%E6%9C%80%E5%B0%91%E6%93%8D%E4%BD%9C%E6%95%B0/" target="_blank">题解地址</a>|<a href="https://letmefly.blog.csdn.net/article/details/151233574" target="_blank">CSDN题解</a>|<a href="https://leetcode.cn/problems/minimum-operations-to-make-the-integer-zero/solutions/3773443/letmefly-2749de-dao-zheng-shu-ling-xu-ya-1x26/" target="_blank">LeetCode题解</a>|
872873
|2760.最长奇偶子数组|简单|<a href="https://leetcode.cn/problems/longest-even-odd-subarray-with-threshold/" target="_blank">题目地址</a>|<a href="https://blog.letmefly.xyz/2023/11/16/LeetCode%202760.%E6%9C%80%E9%95%BF%E5%A5%87%E5%81%B6%E5%AD%90%E6%95%B0%E7%BB%84/" target="_blank">题解地址</a>|<a href="https://letmefly.blog.csdn.net/article/details/134449952" target="_blank">CSDN题解</a>|<a href="https://leetcode.cn/problems/longest-even-odd-subarray-with-threshold/solutions/2529749/letmefly-2760zui-chang-qi-ou-zi-shu-zu-m-f5ob/" target="_blank">LeetCode题解</a>|
873874
|2765.最长交替子数组|简单|<a href="https://leetcode.cn/problems/longest-alternating-subarray/" target="_blank">题目地址</a>|<a href="https://blog.letmefly.xyz/2024/01/23/LeetCode%202765.%E6%9C%80%E9%95%BF%E4%BA%A4%E6%9B%BF%E5%AD%90%E6%95%B0%E7%BB%84/" target="_blank">题解地址</a>|<a href="https://letmefly.blog.csdn.net/article/details/135794883" target="_blank">CSDN题解</a>|<a href="https://leetcode.cn/problems/longest-alternating-subarray/solutions/2617307/letmefly-2765zui-chang-jiao-ti-zi-shu-zu-tddr/" target="_blank">LeetCode题解</a>|
874875
|2766.重新放置石块|中等|<a href="https://leetcode.cn/problems/relocate-marbles/" target="_blank">题目地址</a>|<a href="https://blog.letmefly.xyz/2024/07/25/LeetCode%202766.%E9%87%8D%E6%96%B0%E6%94%BE%E7%BD%AE%E7%9F%B3%E5%9D%97/" target="_blank">题解地址</a>|<a href="https://letmefly.blog.csdn.net/article/details/140686910" target="_blank">CSDN题解</a>|<a href="https://leetcode.cn/problems/relocate-marbles/solutions/2856729/letmefly-2766zhong-xin-fang-zhi-shi-kuai-5j7d/" target="_blank">LeetCode题解</a>|
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
title: 2749.得到整数零需要执行的最少操作数:很独特的一道数学题(多公式硬讲——一步步还真能看懂)
3+
date: 2025-09-05 21:34:33
4+
tags: [题解, LeetCode, 中等, 位运算, 枚举, 数学]
5+
categories: [题解, LeetCode]
6+
---
7+
8+
# 【LetMeFly】2749.得到整数零需要执行的最少操作数:很独特的一道数学题(多公式硬讲——一步步还真能看懂)
9+
10+
力扣题目链接:[https://leetcode.cn/problems/minimum-operations-to-make-the-integer-zero/](https://leetcode.cn/problems/minimum-operations-to-make-the-integer-zero/)
11+
12+
<p>给你两个整数:<code>num1</code> 和 <code>num2</code> 。</p>
13+
14+
<p>在一步操作中,你需要从范围&nbsp;<code>[0, 60]</code> 中选出一个整数 <code>i</code> ,并从 <code>num1</code> 减去 <code>2<sup>i</sup> + num2</code> 。</p>
15+
16+
<p>请你计算,要想使 <code>num1</code> 等于 <code>0</code> 需要执行的最少操作数,并以整数形式返回。</p>
17+
18+
<p>如果无法使 <code>num1</code> 等于 <code>0</code> ,返回 <code>-1</code> 。</p>
19+
20+
<p>&nbsp;</p>
21+
22+
<p><strong>示例 1:</strong></p>
23+
24+
<pre>
25+
<strong>输入:</strong>num1 = 3, num2 = -2
26+
<strong>输出:</strong>3
27+
<strong>解释:</strong>可以执行下述步骤使 3 等于 0 :
28+
- 选择 i = 2 ,并从 3 减去 2<sup>2</sup> + (-2) ,num1 = 3 - (4 + (-2)) = 1 。
29+
- 选择 i = 2 ,并从 1 减去 2<sup>2</sup> + (-2) ,num1 = 1 - (4 + (-2)) = -1 。
30+
- 选择 i = 0 ,并从 -1 减去 2<sup>0</sup>&nbsp;+ (-2) ,num1 = (-1) - (1 + (-2)) = 0 。
31+
可以证明 3 是需要执行的最少操作数。
32+
</pre>
33+
34+
<p><strong>示例 2:</strong></p>
35+
36+
<pre>
37+
<strong>输入:</strong>num1 = 5, num2 = 7
38+
<strong>输出:</strong>-1
39+
<strong>解释:</strong>可以证明,执行操作无法使 5 等于 0 。
40+
</pre>
41+
42+
<p>&nbsp;</p>
43+
44+
<p><strong>提示:</strong></p>
45+
46+
<ul>
47+
<li><code>1 &lt;= num1 &lt;= 10<sup>9</sup></code></li>
48+
<li><code>-10<sup>9</sup>&nbsp;&lt;= num2 &lt;= 10<sup>9</sup></code></li>
49+
</ul>
50+
51+
52+
53+
## 解题方法:数学
54+
55+
这个题解我自己也看了很多遍,如果你想搞懂这道题,请静下心来仔细读读,相信你一定可以搞懂这道题的!哪里不懂欢迎[留言](https://github.com/LetMeFly666/LeetCode/issues/1115)
56+
57+
**k范围浅分析**
58+
59+
假设$num1$减去$k$次$2^i+num2$后变成了$0$,那么有:
60+
61+
$$num_1 - k * num_2 = 2^{i_1} + 2^{i_2} + ... + 2^{i_k}$$
62+
63+
见到$2^{i_1} + 2^{i_2} + ... + 2^{i_k}$应该很敏感才对啊,这不是$2$的幂之和么,只不过加数可以重复。
64+
65+
令等式左边的$num_1 - k * num_2 = x$,那么想让右边的$2^{i_1} + 2^{i_2} + ... + 2^{i_k}=x$,$k$的合法范围是多少?
66+
67+
> 已知$2^{i+1}=2^i+2^i$,所以想让可以使等式成立的$k$比较大的话,可以把一个$2^{i+1}$可以拆成两个$2^i$,最小拆成$2=1+1$为止。也就是说,$x$最多可以由$1+1+1+\dots+1$(共$x$个)组成,也就是说$k$的最大值是$x$。
68+
>
69+
> 那么最小值呢?例如$5=101_{(2)}=2^2+2^0$,$k$最小值为$2$。也就是说对于$x$,$k$的最小值为$x$二进制下$1$的个数。
70+
71+
综上,只要$popcount(x)\leq k\leq x$,就能找到一种方法使得$2^{i_1} + 2^{i_2} + ... + 2^{i_k}=x$。(其中$popcount(x)$是$x$二进制下$1$的个数,$x\gt 0$。
72+
73+
请记住这两个条件:
74+
75+
1. $k\leq x$
76+
2. $k\geq popcount(x)$
77+
78+
**枚举k**
79+
80+
但是别忘了,$x$中还含有变量$k$呢!其中$x=num_1 - k * num_2$。想要判断是返回$k$还是返回$-1$,还得看能不能找到一个$k$使得$popcount(x)\leq k\leq x$,其中$x=num_1 - k * num_2$。
81+
82+
最简单的办法就是**暴力枚举**。令$k$从$1$开始枚举,$1, 2, \cdots$,直到$k$超出“上界”,即$k\gt x$,也就是说$k\gt num_1 - k * num_2$停止。
83+
84+
这里你一定会思考,现在$k$超出上界了,那么我继续增大$k$的话,待会儿$k$会不会就不超出上界了呢?
85+
86+
> 为了探究这个问题,我们把$k$的合法范围处理一下:$k\leq num_1 - k * num_2\Leftrightarrow k*(1+num_2)\leq num_1$。
87+
>
88+
> + 当$1+num_2\leq 0$时,由于数据范围限制$num_1\geq 1$,所以$k*(1+num_2)\leq num_1$恒成立;
89+
> + 当$1+num_2\gt 0$时,可得$k\leq \frac{num_1}{1+num_2}$时$k*(1+num_2)\leq num_1$成立,一旦$k$大于$\frac{num_1}{1+num_2}$该等式就再也不会成立;
90+
>
91+
> 综上,符合假设,不考虑实际算力限制下的超时问题的话,$k$从$1,2,\cdots$枚举到$k\gt x$为止,如果存在$k$满足第二个条件即$k\geq popcount(x)$,我们就能找到了符合条件的$k$;否则,这个枚举范围内没有满足第二个条件的$k$就返回$-1$。
92+
93+
那么$k$的范围究竟是多少呢?暴力枚举会不会超时呢?你别说,还真不会。
94+
95+
因为要想找到一个满足两个条件的$k$,除了一个限制枚举范围的$k\leq x$外,还有一个条件,就是$k\geq popcount(x)$。
96+
97+
我们一直担心的就是会不会$k\leq x$这个条件范围太大,导致$k$一直从$1$枚举到一个非常大的数字(甚至是无穷?),从而超时。
98+
99+
但是别忘了第二个条件$k\geq popcount(x)$是非常容易满足的,要知道$popcount(x)$可是$x$在二进制下$1$的个数,所以先告诉你结论再去证明:$k$最大枚举到几十就会满足第二个条件了。
100+
101+
> $k$的量级是几十(按$10^3$),$num$的量级是$10^9$,所以$x=num_1 - k * num_2$的量级最多为$10^{12}$,$2^40$已经大于$10^{12}$了(不信可以执行下`python -c "print(len(str(2**40)))"`试试),$x$二进制下位数不超过$40$位,就找到满足第二个条件的$k$了。
102+
103+
也就是说实际$k$从$1$开始枚举,最多枚举到$40$,就知道答案了,时间复杂度甚至可以认为是$O(1)$。
104+
105+
+ 时间复杂度$O(1)$
106+
+ 空间复杂度$O(1)$
107+
108+
然后结合实现代码说一下:
109+
110+
```cpp
111+
int makeTheIntegerZero(int num1, int num2) {
112+
for (int k = 1; k <= num1 - (long long)num2 * k; k++) {
113+
if (k >= __builtin_popcountll(num1 - (long long)num2 * k)) {
114+
return k;
115+
}
116+
}
117+
return -1;
118+
}
119+
```
120+
121+
关于这个循环的范围:
122+
123+
+ 如果$1+num_2\gt 1$,那么要么`for`循环先终止返回`-1`(如`num1=16, num2=10`会在`k=2`时结束for循环),要么`if`条件先命中`return k`。
124+
+ 如果$1+num_2\leq 0$,`for`循环相当于`while true`,但是里面的`if`条件一定会很快满足,并`return k`。
125+
126+
总之$k$枚举不会超过$40$次。解喽。这还真不好想。
127+
128+
### AC代码
129+
130+
#### C++
131+
132+
```cpp
133+
/*
134+
* @Author: LetMeFly
135+
* @Date: 2025-09-05 18:29:32
136+
* @LastEditors: LetMeFly.xyz
137+
* @LastEditTime: 2025-09-05 21:33:38
138+
*/
139+
#if defined(_WIN32) || defined(__APPLE__)
140+
#include "_[1,2]toVector.h"
141+
#endif
142+
143+
/*
144+
nums1 - k * nums2 = 2^{i_1} + 2^{i_2} + ... + 2^{i_k}
145+
*/
146+
class Solution {
147+
public:
148+
int makeTheIntegerZero(int num1, int num2) {
149+
for (int k = 1; k <= num1 - (long long)num2 * k; k++) {
150+
if (k >= __builtin_popcountll(num1 - (long long)num2 * k)) {
151+
return k;
152+
}
153+
}
154+
return -1;
155+
}
156+
};
157+
```
158+
159+
> 同步发文于[CSDN](https://letmefly.blog.csdn.net/article/details/151233574)和我的[个人博客](https://blog.letmefly.xyz/),原创不易,转载经作者同意后请附上[原文链接](https://blog.letmefly.xyz/2025/09/05/LeetCode%202749.%E5%BE%97%E5%88%B0%E6%95%B4%E6%95%B0%E9%9B%B6%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84%E6%9C%80%E5%B0%91%E6%93%8D%E4%BD%9C%E6%95%B0/)~
160+
>
161+
> 千篇源码题解[已开源](https://github.com/LetMeFly666/LeetCode)

0 commit comments

Comments
 (0)