位运算在一些问题上总能发挥一些意想不到的优势,不过对于不是对其有一定理解的coder,位运算解决问题相对晦涩;
我按照使用功能上 为大家整理了一些技巧供大家参考,一般无须过多深究。
实用功能 三四五 ~~
一、将26个英文字符大写转小写,小写转大写,大小写互换。
(1)大写转小写: ('a' | ' ') = 'a' ; ('A' | ' ') = 'a';
(2)小写转大写: ('a' & '_') = 'A' ; ('A' & '_') = 'A';
(3)大小写互换: ('a' ^ ' ') = 'A' ; ('A' ^ ' ') = 'a';
这个用处不大,原理也很简单,就是ascii码经过对应的转换。
二、不使用第三个变量交换两个变量的值。
int a = 1, b = 2;
a = a ^ b
b = a ^ b
a = a ^ b
// a, b = 2, 1
这个方法实际用处好像也不大,面试可能会用到,与python中的 a, b = b, a 交换引用 都算解决的方式。
三、判断两个数是否异号。
int x = -1, y = 2;
bool f = ((x ^ y) < 0; //true
int x = 1, y = 3;
bool f = ((x ^ y) < 0; //false
这一点对比常规判断方法还是比较方便的。比较推荐小伙伴们记下。
四、n & (n - 1)的用法。
这个操作的作用是消除数字 n 的二进制表示中的最后一个 1。
举个列子 n 的 二进制是 0 0 0 0 0 1 1 0 0 0
n-1 之后变成 0 0 0 0 0 1 0 1 1 1 (上面的n 从低位到高位起 第一个不为0的数 借1,就有了下面这种情况,可以自己想一下)
按位与之后 0 0 0 0 0 1 0 0 0 0 (对比n发现消除了最后一个1)
在明白作用之后 就衍生出了一些奇妙的用途。
(1) 判断一个数是不是2的指数(都是大于0 的数)。
因为如果一个数是2的指数的话,它的二进制表示就绝对是只有一个1 存在,例如 2 ** 3 == 8 (0000 0100),这也不难理解因为每一个位 都是2的指数。
这样就可以直接使用 n & (n-1) 消除仅有的一个1,判断是否为0即可
例如 16 & (16 - 1) == 0 // 16 == 2 ** 4
五、使用 ^(异或)判断一个数组中仅出现一次的数字(这个数字唯一,且其他数字出现偶次数)
单独写这个用法是因为在leetcode上136题只出现一次的数字中 得到了充分应用~
nums = [2,5,2,3,3,5,3,3,4,7,7]
【Java】
public static int singleNumber(int[] nums) { int num = 0; for (int i = 0; i < nums.length; i++) { num = num ^ nums[i]; } return num; }
【Python】
return reduce(int.__xor__, nums)
相信一些同学在初期不太容易想到这样的方法,那么就算我们暂时没有这样的思路也要知其所以然,为什么异或可以实现。
因为异或运算存在一些规律,满足了交换律和结合律。
普通规律: x ^ 0 = x ;
x ^ x = 0 ;
结合律和交换律:
a ^ a ^ b ^ c ^ d ^ c ^ d == (a ^ a) ^ (c ^ c) ^ (d ^ d) ^ b == 0 ^ 0 ^ 0 ^ b == b