位运算
位运算基础
- &
- 按位与
- 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
- |
- 按位或
- 两个相应的二进制位中只要有一个为1,该位的结果值为1
- ^
- 按位异或
- 若参加运算的两个二进制位值相同则为0,否则为1
- ~
- 取反
- ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1
- <<
- 左移
- 用来将一个数的各二进制位全部左移N位,右补0
- >>
- 右移
- 将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数, 高位补0
奇淫巧技
1、用于消去x的最后一位的1
x & (x-1)
x = 1100
x-1 = 1011
x & (x-1) = 1000
应用:
应用一 用O(1)时间检测整数n是否是2的幂次.
思路解析:N如果是2的幂次,则N满足两个条件。
- N>0
- N的二进制表示中只有一个1
一位N的二进制表示中只有一个1,所以使用N&(N-1)将唯一的一个1消去。如果N是2的幂次,那么N&(N-1)得到结果为0,即可判断。
应用二 计算在一个 32 位的整数的二进制表示中有多少个 1.
思路解析:
由 x & (x-1) 消去x最后一位知。循环使用x & (x-1)消去最后一位1,计算总共消去了多少次即可。
应用三 将整数A转换为B,需要改变多少个bit位
思路解析
这个应用是上面一个应用的拓展。
思考将整数A转换为B,如果A和B在第i(0<=i<32)个位上相等,则不需要改变这个BIT位,如果在第i位上不相等,则需要改变这个BIT位。所以问题转化为了A和B有多少个BIT位不相同。联想到位运算有一个异或操作,相同为0,相异为1,所以问题转变成了计算A异或B之后这个数中1的个数。
2、使用二进制进行子集枚举
应用.给定一个含不同整数的集合,返回其所有的子集
样例
如果 S = [1,2,3],有如下的解:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2] ]
思路
思路就是使用一个正整数二进制表示的第i位是1还是0,代表集合的第i个数取或者不取。所以从0到2n-1总共2n个整数,正好对应集合的2^n个子集。
3、abb=a
异或运算支持运算的交换律和结合律
应用一 数组中,只有一个数出现一次,剩下都出现两次,找出出现一次的。
问题
Given [1,2,2,1,3,4,3], return 4
解题思路
因为只有一个数恰好出现一个,剩下的都出现过两次,所以只要将所有的数异或起来,就可以得到唯一的那个数。
应用二 数组中,只有两个数出现一次,剩下都出现两次,找出出现一次的
问题
Given [1,2,2,3,4,4,5,3] return 1 and 5
解题思路
有了第一题的基本的思路,我们不妨假设出现一个的两个元素是x,y,那么最终所有的元素异或的结果就是res = x^y。并且res!=0,那么我们可以找出res二进制表示中的某一位是1,那么这一位1对于这两个数x,y只有一个数的该位置是1。对于原来的数组,我们可以根据这个位置是不是1就可以将数组分成两个部分。求出x,y其中一个,我们就能求出两个了。
其他应用场景
判断奇偶数
if(n & 1 == 1){
// n 是个奇数。
}
交换两个数
异或运算支持运算的交换律和结合律
x = x ^ y // (1)
y = x ^ y // (2)
x = x ^ y // (3)