位运算面试题 python

首先你要明白的几个知识点:
(1)在计算机里面,负数是以补码存储的
(2)原码求补码:取反,+1
(3)补码求原码:取反,+1
(4)取反操作是在原码上进行的!

  • 0s 表示一串 0,1s 表示一串 1。|:按位取或。~:按位取反。~x 类似于 -x-1。如:~-6: 5
 -6的补码是+60000 0110)取反后再+1,为(1111 1001+0000 0001=1111 1010,
,也就是计算机中-6是用(1111 1010)来存储的,(1111 1010) 按位取反得到(0000 0101)这就是答案5
4的原码: 0000 0100,取反得到: 1111 1011, 观察符号,是负数,因为负数以补码存储的,所以问题转化为: 
某个数x的补码是1111 1011,求x的值(由补码求原码) 取反: 0000 0100+1: 0000 0101 = 5, 
加上标点符号(负号) 得到结果: -5
```python
因为-5是负数,所以它是以5的补码表示的,所以转化为已知5的补码,求对应的原码,然后在取反. 
5补码: 0000 0101, 
取反: 1111 1010 
+1: 1111 1011, 得到原码 
取反: 0000 0100 = 4 ,加上标点负号(正号)得到结果:4


```python
x ^ 0s = x      x & 0s = 0      x | 0s = x
x ^ 1s = ~x     x & 1s = x      x | 1s = 1s
x ^ x = 0       x & x = x       x | x = x
  • 利用 x ^ 1s = ~x 的特点,可以将一个数的位级表示翻转;利用 x ^ x = 0 的特点,可以将三个数中重复的两个数去除,只留下另一个数。
  • 利用 x & 0s = 0 和 x & 1s = x 的特点,可以实现掩码操作。一个数 num 与 mask:00111100 进行位与操作,只保留 num 中与 mask 的 1 部分相对应的位。
01011011 &
00111100
--------
00011000
  • 利用 x | 0s = x 和 x | 1s = 1s 的特点,可以实现设值操作。一个数 num 与 mask:00111100 进行位或操作,将 num 中与 mask 的 1 部分相对应的位都设置为 1。
01011011 |
00111100
--------
01111111

位与运算技巧

  • n&(n-1) 去除 n 的位级表示中最低的那一位 1。例如对于二进制表示 01011011,减去 1 得到 01011010,这两个数相与得到 01011010。
01011011 &
01011010
--------
01011010
  • n&(-n) 得到 n 的位级表示中最低的那一位 1。-n 得到 n 的反码加 1,也就是 -n=~n+1。例如对于二进制表示 10110100,-n 得到 01001100,相与得到 00000100。
10110100 &
01001100
--------
00000100
  • n-(n&(-n)) 则可以去除 n 的位级表示中最低的那一位 1,和 n&(n-1) 效果一样。

移位运算

>> n 为算术右移,相当于除以 2n,例如 -7 >> 2 = -2。

11111111111111111111111111111001  >> 2
--------
11111111111111111111111111111110

>>> n 为无符号右移,左边会补上 0。例如 -7 >>> 2 = 1073741822。

11111111111111111111111111111001  >>> 2
--------
00111111111111111111111111111111

<< n 为算术左移,相当于乘以 2n。-7 << 2 = -28。

11111111111111111111111111111001  << 2
--------
11111111111111111111111111100100

mask 计算

  • 要获取 111111111,将 0 取反即可,~0。
  • 要得到只有第 i 位为 1 的 mask,将 1 向左移动 i-1 位即可,1<<(i-1) 。例如 1<<4 得到只有第 5 位为 1 的 mask :00010000。
  • 要得到 1 到 i 位为 1 的 mask,(1<<i)-1 即可,例如将 (1<<4)-1 = 00010000-1 = 00001111。
  • 要得到 1 到 i 位为 0 的 mask,只需将 1 到 i 位为 1 的 mask 取反,即 ~((1<<i)-1)。
  1. 统计两个数的二进制表示有多少位不同
class Solution(object):
    def hammingDistance(self, x, y):
        """
        :type x: int
        :type y: int
        :rtype: int
        """
        return bin(x^y).count("1")
        # (1^4)的结果是5,即0001^0100=0101=5。bin返回的是字符串,bin(10)返回'0b1010'
  1. 数组中唯一一个不重复的元素
class Solution(object):
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 任何数于0异或为任何数 0 ^ n => n
        # 相同的数异或为0: n ^ n => 0
        # 交换律:a ^ b ^ c <=> a ^ c ^ b
        res=0
        for num in nums:
            res^= num
        return res
  1. 找出数组中缺失的那个数
class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        res = len(nums)
        for idx, num in enumerate(nums):
            res ^= idx ^ num
        return res
  1. 数组中不重复的两个元素
class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        # 参考官方题解
        # difference between two numbers (x and y) which were seen only once
        bitmask = 0
        for num in nums:
            bitmask ^= num
        
        # rightmost 1-bit diff between x and y
        diff = bitmask & (-bitmask)
        
        x = 0
        for num in nums:
            # bitmask which will contain only x
            if num & diff:
                x ^= num  # 这里是多次异或找到diff为1的位上只出现1次的数。
        
        return [x, bitmask^x]
  1. 翻转一个数的比特位
class Solution:
    def reverseBits(self, n: int) -> int:
        res, power = 0, 31
        while n:
            res += (n & 1) << power # n&1能看最后一位是0还是1
            n = n >> 1 # 最后一位不见了
            power -= 1
        return res
  1. 不用额外变量交换两个整数
a = a ^ b
b = a ^ b
a = a ^ b
  1. 判断一个数是不是 2 的 n 次方
class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        return n > 0 and n & (n - 1) == 0 
  1. 判断一个数是不是 4 的 n 次方
class Solution:
    def isPowerOfFour(self, num: int) -> bool:
        return num > 0 and num & (num - 1) == 0 and num % 3 == 1

9.7看完了

  1. 判断一个数的位级表示是否不会出现连续的 0 和 1
class Solution:
    def hasAlternatingBits(self, n: int) -> bool:
        return not ('11' in str(bin(n)) or '00' in str(bin(n))) 
class Solution:
    def hasAlternatingBits(self, n: int) -> bool:
        tmp = n^(n>>1)
        return tmp&(tmp+1) == 0
  1. 求一个数的补码
class Solution:
    def findComplement(self, num: int) -> int:
        # num和补数相加,就是满数位1的二进制数,即2**(n-1)-1
        return 2**(len(bin(num))-2)-num-1
class Solution:
    def findComplement(self, num: int) -> int:
        count, n = 0, num
        while n > 0:
            count += 1
            n = n >> 1
        all_bits = pow(2, count) - 1
        return num ^ all_bits
  1. 实现整数的加法
class Solution(object):
    def getSum(self, a, b):
        """
        :type a: int
        :type b: int
        :rtype: int
        """
        # python整数类型为无限长整数类型.需要0x100000000取模,保证该数从32位开始到最高位都是0。其中0x表示16进制,8个0转为2进制就是32个0。
        # a+b的问题拆分为(a和b的无进位结果) + (a和b的进位结果)
        # 无进位加法使用异或运算
        # 进位结果使用与运算和移位运算
        # 循环此过程,直到进位为0
        mask = 0x100000000
        max_int = 0x7FFFFFFF  # F:1111,7:0111。0x7FFFFFFF的二进制表示是首位是0,其余都是1。第一位是符号位,0 表示他是正数,就是说,这是最大的整型数int。
        min_int = max_int + 1
        while b != 0:
            carry = (a & b) << 1 # 计算进位。
            a = (a ^ b) % mask # 无进位加法,对0x100000000取模,保证该数从32位开始到最高位都是0。# 取余范围限制在 [0, 2^32-1] 范围内
            b = carry % mask
        return a if a <= max_int else ~((a % min_int) ^ max_int)  # ~((a % MIN_INT) ^ MAX_INT) 其实可以简化为~(a ^ mask) 为什么要对负数做这样的处理呢?因为在python中int不是32位的,输出是64位,所以一个负数比如-2, 64位表示就是0x00000000FFFFFFFE, 用python求取这个16进制的值int('0x00000000FFFFFFFE', 16), 得到的数字是4294967294 不是我们想要的-2,所以: a^mask是先对a的前32位取反,对应-2,就得到0x0000000000000002 再用~操作符对所以位置取反,对应-2,得到0xFFFFFFFFFFFFFFFE总结一下就是,由于oj系统python最后返回的是64位,如果不对负数特殊处理,那么负数的前32位是0,最后输出的是大于32位的正数。
  1. 字符串数组最大乘积
class Solution:
    def maxProduct(self, words: List[str]) -> int:
        n = len(words)
        masks = [0] * n
        lens = [0] * n
        bit_number = lambda ch : ord(ch) - ord('a')
        
        for i in range(n):
            bitmask = 0
            for ch in words[i]:
                # add bit number bit_number in bitmask
                bitmask |= 1 << bit_number(ch)
            masks[i] = bitmask
            lens[i] = len(words[i])
            
        max_val = 0
        for i in range(n):
            for j in range(i + 1, n):
                if masks[i] & masks[j] == 0:
                    max_val = max(max_val, lens[i] * lens[j])
        return max_val
  1. 统计从 0 ~ n 每个数的二进制表示中 1 的个数
class Solution(object):
    def countBits(self, num):
        """
        :type num: int
        :rtype: List[int]
        """
        res = [0]
        for i in range(1, num + 1):
            if i % 2 == 0: 
                res.append(res[i/2])
            else:
                res.append(res[i - 1] + 1)
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值