剑指offer 2.4.3 位运算
参考:
概念
位运算是把数字用二进制表示之后,对每一位上0或者1的运算。
总共只有五种运算:与、或、异或、左移和右移。
- 左移运算符m<<n:表示把m左移n位。左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0。
比如:00001010<<2=00101000 - 同理,右移运算符m>>n表示把m右移n位。比如:10001010<<3=01010000
- 特殊地,如果数字是一个有符号数值,则用数字的符号位填补最左边的n位。
- 如果数字原先是一个正数,则右移之后在最左边补n个0;
- 如果数字原先是负数,则右移之后在最左边补n个1。
把整数右移一位和把整数除以2在数学上是等价的,那上面的代码中可以把右移运算换成除以2吗?
- 答案是否定的。因为除法的效率比移位运算要低得多,在实际编程中应尽可能地用移位运算符代替乘除法。
面试题10:二进制中1的个数
题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。
思路解析
1 可能会引起死循环
原始 n 循环地左移一位和右移一位的方法,因为Python不会出现整数溢出的情况,这里就不再考虑着两种方法。
2 聪明: n = n & ( n − 1 ) n = n\&(n-1) n=n&(n−1)
- 注意:每个非零整数n和n-1进行按位与运算 n & ( n − 1 ) n \& (n-1) n&(n−1),整数n的二进制数中最右边的1就会变成0;
- 那么二进制数中的1的个数就会减少一个,因此可以利用一个循环,使得 n = n&(n-1) ,计算经过几次运算减少到0,就是有几个1。
def NumberOf1InBinary(n):
cnt = 0
if n < 0:
# 十六进制,8个f
n = n&(0xffffffff)
while n:
n = n & (n-1)
cnt += 1
return cnt
或者调用python的元方法,直接求出二进制字符串,并且使用count计数。
def NumberOf1InBinary(n):
cnt = 0
if n < 0:
# 十六进制,8个f
n = bin(n&(0xffffffff))
while n:
n = bin(n)
return n.count('1')
扩展题目1
用一条语句判断一个整数是不是2的整数次方。
解析:
一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0。
由上一个题目可知,符合
n
&
(
n
−
1
)
=
0
n \& (n-1)=0
n&(n−1)=0.
扩展题目2
输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。
解析:
第一步求这两个数的异或,第二步统计异或结果中1的位数。