1、题目
1.1 问题描述
小C在学习二进制运算,他了解到每个非负整数都有其二进制表示。例如,整数 5 可以被表示为二进制 "101",整数 11 可以被表示为二进制 "1011",并且除了 N = 0 外,任何二进制表示中都不含前导零。
二进制的反码表示是将每个 1 变为 0,每个 0 变为 1。例如,二进制数 "101" 的二进制反码为 "010"。现在小C想知道,给定一个十进制数 N,它的二进制反码对应的十进制数是多少。
1.2 测试样例
样例1:
输入:
N = 5
输出:2
样例2:
输入:
N = 10
输出:5
样例3:
输入:
N = 0
输出:1
2、思路
根据题意可以看出要求一个十进制数的反码,那么我们先把它的二进制形式表示出来再做下一步打算(这里先不使用python的内置函数,后面会讲到用内置函数)。现在假设我们的电脑是32位机,那么一个十进制数在计算机中就是由32位二进制比特构成,我们以十进制数11为例。
11的二进制:0000....00101111的二进制取反:1111....110100
那在代码中我们怎么做到这一点呢?相信大家都已经想到了,那就是异或相同位数的1。所谓异或可以理解为无进位相加,比如5^3=6,具体怎么算的呢?我们先来写出它们的二进制形式,然后对应的二进制位相加,产生的进位丢掉。
5的二进制:0000....0001013的二进制:0000....000011- 无进位相加操作后:
0000....000110
现在,我们已经了解了什么是异或,我们就可以利用它来对11进行取反,只需将0000....001011异或上1111....111111即可,得到的结果就是1111....110100。可是,这不是我们题目中所要的,题目中要求的二进制不包含前导0。那么我们只要把1111....111111前面那些没用的1改成0不就可以了,将其改为0000....001111。
总结一下,整体的解题思路:
- 首先,判断题目给出的数的二进制形式最左边的
1到末尾的长度,记为count。 - 其次,将
1左移count位再减1,构造出左边32-count位全0,右边count位全1。- 为什么减
1:比如11求得的count应为4,就要构造0000....001111。1左移4位后变为0000....010000,再减去1后就变为想构造的二进制数了。
- 为什么减
- 最后,将构造好的数和给定的数做异或即可。
3、代码
3.1 计算给定数值二进制最左边的1到末尾的长度
def len(N: int) -> int:
"""计算整数 N 的二进制表示中最左边的 1 到末尾的长度。"""
count = 0
while N != 0: # 还没有遍历到最左边的 1 时
N >>= 1 # 右移一位
count += 1 # 计数加 1
return count
3.2 构造所需的二进制数并求得最终结果
def solution(N: int) -> int:
"""计算给定整数 N 的二进制反码对应的十进制数。"""
if N == 0:
return 1 # 如果 N 为 0,返回 1
# 计算 N 的二进制表示中有效位的数量
count = len(N)
# 构造所需的二进制
num = (1 << count) - 1
# 使用异或操作得到 N 的反码
return N ^ num
4、运行结果
可以看到提交通过,说明我们的方法和代码都没有问题。
5、对比分析
其实,如果这道题目直接使用python的内置函数更简单,代码量更少,代码如下:
def solution(N: int) -> int:
if N == 0:
return 1
# 获取二进制表示,并去掉前导 '0b'
binary = bin(N)[2:]
# 对二进制字符串进行反码操作
inverted_binary = ''.join('1' if bit == '0' else '0' for bit in binary)
# 将反码转换回整数
return int(inverted_binary, 2)
但是,同样都是时间复杂度为O(log N)的算法,想看哪个更快就需要比较时间常数,python内置函数的方法需要将数值转换为二进制的字符串形式进行拼接操作,而上面讲到的方法只涉及数值的位操作、加减操作等。我们都知道数值操作要比字符串操作快,所以上面讲述的方法性能更好。
6、总结
最后,想给刚入门的同学一些建议(其实我也没入门多久,也比较菜),遇到不会的题可以使用AI来快速获得解题思路(虽然有可能不对,但能提示你往正确的方向去想),这样可以大大提高效率。此外,还要多刷题,多看题解,没事的时候也可以去打打比赛什么的,长一些见识。做得多了,看得多了,之后再做题自然而然就能想到好的解题思路了。