LC 476. 数字的补数
题目描述
这是 LeetCode 上的 476. 数字的补数 ,难度为 简单。
对整数的二进制表示取反(0
变 1
,1
变 0
)后,再转换为十进制表示,可以得到这个整数的补数。
- 例如,整数
5
的二进制表示是"101"
,取反后得到"010"
,再转回十进制表示得到补数 2 。
给你一个整数num
,输出它的补数。
示例 1:1
2
3
4
5输入:num = 5
输出:2
解释:5 的二进制表示为 101(没有前导零位),其补数为 010。所以你需要输出 2 。
示例 2:1
2
3
4
5输入:num = 1
输出:0
解释:1 的二进制表示为 1(没有前导零位),其补数为 0。所以你需要输出 0 。
提示:
- $1 <= num < 2^{31}$
模拟(遍历)
返回对 $num$ 的二进制表示取反的数,注意 $num$ 的二进制表示是不包含前导零的。
因此主要问题求得 $num$ 最高位 $1$ 的位置。
一个简单的做法是:先对 $num$ 进行「从高到低」的检查,找到最高位 $1$ 的位置 $s$,然后再对 $num$ 进行遍历,将低位到 $s$ 位的位置执行逐位取反操作。
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Solution {
public int findComplement(int num) {
int s = -1;
for (int i = 31; i >= 0; i--) {
if (((num >> i) & 1) != 0) {
s = i;
break;
}
}
int ans = 0;
for (int i = 0; i < s; i++) {
if (((num >> i) & 1) == 0) ans |= (1 << i);
}
return ans;
}
}
- 时间复杂度:$O(\log{num})$
- 空间复杂度:$O(1)$
模拟(lowbit)
通过解法一我们发现,如果 $num$ 的二进制表示中最高位 $1$ 的位置为 $s$ 的话,那么实际上我们只需要对 $num$ 的前 $s - 1$ 位进行取反即是答案(第 $s$ 位的取反结果始终为 $0$)。
因此我们可以先使用 lowbit
操作来得到 $num$ 二进制表示中最高位 $1$ 的位置为 $1$,其余位为 $0$ 时所代表的数字 $x$。
然后 $x - 1$ 即是二进制表示中前 $s - 1$ 位均为 $1$,其余位为 $0$ 的数字,将其与 $num$ 的取反数执行「按位与」操作,即可达到「仅对 $num$ 的前 $s - 1$ 位进行取反」的效果。
代码:1
2
3
4
5
6
7class Solution {
public int findComplement(int num) {
int x = 0;
for (int i = num; i != 0; i -= i & -i) x = i;
return ~num & (x - 1);
}
}
- 时间复杂度:$O(\log{num})$
- 空间复杂度:$O(1)$
最后
这是我们「刷穿 LeetCode」系列文章的第 No.476
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!