位运算

6.运算符

6.1原码、反码和补码

二进制有三种不同的表示形式:原码、反码和补码,计算机内部使用补码来表示
原码:就是二进制的表示(注意,最高位是符号位)。

00 00 00 11 -> 3
10 00 00 11 -> -3

反码:正数的反码就是原码,负数的反码是符号位不变,其余位取反(对应正数按位取反)。

00 00 00 11 -> 3
11 11 11 00 -> -3

补码:正数的补码就是原码,负数的补码是反码+1。

00 00 00 11 -> 3
11 11 11 01 -> -3

符号位:最高位为符号位,0表示正数,1代表负数。在位运算中符号位也参与运算。

6.2按位非操作~

~1 = -2
~0 = -1

~把num的补码中的0和1全部取反,有符号位正数的符号位在~运算中同样会取反。

00 00 01 01 -> 5
~
11 11 10 10 -> -6


11 11 10 11 -> -5
~
00 00 01 00 -> 4
#例子1:
~4
#-5

#例子2:
~-5
#4

6.3按位与操作 &

例:
1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0

两个数对应的二进制数两个对应位都为1才是1,否则位0

00 00 01 01 -> 5
&
00 00 01 10 -> 6
---
00 00 01 00 -> 4
例子1:
5 & 6
# 4

6.4按位或操作 |

例:
1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0

只要两个对应的二进制数对应的位置上有一个为1则为1,否则为0。

00 00 01 01 -> 5
|
00 00 01 10 -> 6
---
00 00 01 11 ->7    

6.5按位异或操作 ^

例:
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

对应的两个二进制数,在每个位置上,对应位不相同时为1,否则为0。

00 00 01 01 -> 5
^
00 00 01 10 -> 6
---
00 00 00 11 -> 3

且异或操作是满足交换律结合律的:

对应的两个数A,B满足
A^B = B^A
A^A = 0
A^0 = A
A^B^A = A^A^B = B

6.6按位左移操作 <<

num << i :意味着将num的二进制表示向左移动i个位置所得到的值。

00 00 10 11 -> 11
11 << 3
---
01 01 10 00 -> 88

6.7按位右移操作 >>

num >> i:意味着将num的二进制表示向右移i个位置所得到的值。

00 00 10 11 -> 11
11 >> 2
---
00 00 00 10 -> 2

6.8利用位运算实现快速计算

1.可以通过<<和>>来快速计算2的背倍数问题。

n << 1 -> 计算n^2
n >> 1 -> 计算n/2,负奇数的运算不可用
n << m -> 计算n*(2^m)
n >> m -> 计算n/(2^m)
1 << n -> 2^n

2.通过^快速交换两个整数。

a ^= b
b ^= a
a ^= b
#利用异或交换两个整数的例子
a = 2
b = 1
a = a^b # a = 3
b = b^a # b = 2
a = a^b # a = 1
#所以经过上述操作后a = 1, b =2,完成了整数的交换。

3.通过a & (-a)快速获取a的最后为1位置的整数。

例1:
00 00 01 01 -> 5
&
11  11 10 11 -> -5
---
00 00 00 01 -> 1

例2:
00 00 11 10 -> 14
&
11 11 00 10 -> -14
---
00 00 00 10 -> 2

6.9利用位运算实现整数集合

一个数的二进制表示可以看作是一个集合(0代表不在集合中,1代表在集合中)。
比如集合{1, 3, 4, 8},可以表示为二进制数01 00 01 10 10 而对应的位运算也可以看作是对集合的操作。
元素与集合的操作:

a | (1<<i) -> 把i插入到集合中
a & ~(1<<i) -> 把i从集合中删除
a & (1<<i) ->判断i是否属于集合

集合间的操作:

a补 -> ~a
a交b -> a&b
a并b -> a|b
a差并 -> a & (-b)

注:整数在内存中是以补码形式存在的,输出自然也是按照补码输出的。

#Python中的bin()输出:
bin(3) # 0b11
bin(-3) # -0b11

bin(-3 & 0xffffffff)
# 0b11111111111111111111111111111101

bin(0xfffffffd)
# 4294967293

从结果我们可以看出来:

  • Python中bin一个负数,输出的是它的原码的二进制表示加上一个负号。
  • Python中的整型是补码形式存储的。
  • Python中整型是不限制长度的不会超范围溢出。

所以为了获得负数(十进制的)的补码,需要手动将其和十六进制数0xffffffff进行按位与操作,再给bin()进行输出,得到的负数才是补码表示。

练习题:
Leetcode 136:只出现一次的数字
给定一个非空数组,除了某个元素只出现过一次以外,其余每个元素都出现两次,找出那个只出现了一次的元素。尝试使用位运算解决这个问题。

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        #数学方法
        #sum1 = sum(set(nums))
        #return 2 * sum1 - sum(nums)

        #异或方法
        a = 0
        for i in nums:
            a ^= i
        return a
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值