位运算
位运算基础概念以及题目:
概念
位与
符号:&
12&10—->1100&1010(转换为二进制)
从低到高按位运算,当两个数字都为1,结果才为1,否则为0,因此结果为1000,也就是8
位或
符号:|
12|10——->1100|1010
从低到高按位运算,当两个数字都为0,结果才为0,否则为1,因此结果为1110,也就是14
小概念:相同的数异或为0,任何数与0异或为它本身,满足交换律和结合律
异或
符号:^
12\^10——->1100^1010
从低到高按位运算,当两个数字都不同,结果才为1,否则为0,因此结果为0110,也就是6。
从结果来看,异或可以看作不进位的加法
左移
符号:<<
12<<3----->1100<<3
想左移三位,末尾补零,因此结果为1100000.另外,左移一位可以看作该数字乘二。
右移
符号: >>
12>>3——->1100>>3=1
右移三位,右移一位可看作除二向下取整
例题
2的幂
https://leetcode.cn/problems/power-of-two/
bool isPowerOfTwo(int n){ |
解析:当一个数为2的幂时,他的表达方式一定为100000….,这个数n表达方式固定,n-1则确定为0111111….。因此对n和n-1取位与,结果一定为1,因此可判断。
4的幂
https://leetcode.cn/problems/power-of-four/
解析:分析可知:$2^{2x}mod 3=1$ 且 $2^{2x+1}mod 3=2$ 因此可以得出结论$4^xmod3=1$ 。因此,当一个数n是2的幂,同时模3为1,则他一定是4的幂
bool isPowerOfFour(int n){ |
位1的个数
https://leetcode.cn/problems/number-of-1-bits/
解析:任何一个数字的二进制表示必然可以表示为0,1的组合,当一个数字的二进制形式为….1000时我们把它减去1,则变为形式…..0111,当我们把这两个数进行位与运算,得到的结果为…..0000。我们发现最末尾的1被我们消除了,当我们重复这个过程,在这个过程中记录进行的次数,当最后n变为0时,计数结果就为1的个数。
int hammingWeight(uint32_t n) { |
交换数字
https://leetcode.cn/problems/swap-numbers-lcci/
解法:
- a=a\^b
- b=a\^b=a\^b\^b=a\^0=a
- a=a\^b=a\^a\^b=b
/** |
只出现一次的数字
https://leetcode.cn/problems/single-number/
int singleNumber(int* nums, int numsSize){ |
解法:很巧妙的解法,根据异或的性质,我们发现当我们从头开始循环异或,出现两次的数必然可以结合异或结果为0,最后只剩下异或结果为本身的数,这个数就是出现一次的数。(草,真的牛逼)
汉明距离
https://leetcode.cn/problems/hamming-distance/
解析:把两个数字异或,我们发现结果为1的位上就是两个数字对应二进制位不同的位置,因此我们把异或后的结果进行1消去,同时统计1的个数,答案就是汉明距离。
int hammingDistance(int x, int y){ |
交替位二进制数
https://leetcode.cn/problems/binary-number-with-alternating-bits/
解析:题目意思可以视为判断数字n的二进制表达形式是否为01连续出现,我们判断当00和11出现时对应的十进制数字为0和3,因此我们将数字n与3位与,如果符合题意,得到的结果只能是10或者01,即为1,2,如果出现0,3,则说明n中出现了00,11的组合,则返回false。
bool hasAlternatingBits(int n){ |
找出所有子集的异或总和再求和
https://leetcode.cn/problems/sum-of-all-subset-xor-totals/
解析:这个题我搞了半天(md我怎么这么菜),首先是我们要明白一个数组的子集个数是2的元素个数的次方,因此第一个循环是为了找到所有的子集,当我们找到所有子集之后,我们要对每一个子集进行分析,因为集合中的元素在子集中只会有两种状态,0(未出现)和1(出现),因此,每个子集都可以表示为一个二进制数字,比如数组[2,3,4]的子集之一[2,3],用相对应的二进制数字来表示就是110。这样表示完每一个子集后,我们对每一个二进制数进行分析,当我们在二进制数中寻找到1时,说明对应的数组nums[i]在子集中存在,就可以进行异或操作了,而寻找二进制数中的1可以用一个表达式来解决:i&(1<<j)。意思是寻找二进制数i在第j位是否为1。当第二次循环遍历二进制数位数之后,我们就可以确定存在的元素,就可以进行必要的异或和相加的操作了。
int subsetXORSum(int* nums, int numsSize){ |
两整数之和
阴间题目,要求不能用+,-完成两数求和。
https://leetcode.cn/problems/sum-of-two-integers/
int getSum(int a, int b){ |
分析:首先已知a\^b可以表示为不考虑a和b的情况下a和b的加和,因此我们要找到进位情况下进的位的那个数字,是(a&b)<<1,因此呢我们只要递归运算a\^b和(a&b)<<1的和即可。每次当我们进行(a&b)<<1时,产生的结果0,1分别代表着不进位,进位。因此,如果不进位,结果就是a\^b,即返回函数参数“a”。而当结果不为0,即连个数字都为1时,需要进位,进位则表示着这一个1在后一位相加,而后一位的相加同样可以表示为上述过程,仔细思考可以发现,递归出口在函数参数”b”为0的时候,这个时候进位完毕,输出结果a\^b就是最后答案。
插入
https://leetcode.cn/problems/insert-into-bits-lcci/
int insertBits(int N, int M, int i, int j){ |
解析:博主摆烂了…