如何从十进制转换为二进制
位运算符
左移 << 譬如 0011 => 0110
右移 >> 譬如 0110 => 0011
这里作为演示用4个二进制位,在计算机中老式计算机是32位,新计算机基本都是64位
按位或 |
按位与 &
按位取反 ~
按位异或(相同为0不同为1) ^
XOR-异或 :相同为0, 不同为1. 也可用"不进位加法"来理解
异或操作的特点:
x ^ 0 = x // x和0相同为0, 不同为1, 所以x ^ 0 就是x 本身, x异或全0 等于x
x ^ 1s = ~x // x异或全1 这里的1s指的全1, 全1就是0取反 注意 1s = ~0, x异或全1等于x取反
x ^ (~x) = 1s // x异或x取反(所有二进制位0变1,1变0), 那么x与 ~x所有二进制位都不同,异或出来的结果为全1
x ^ x = 0 // x异或x它们的所有二进制位都相同,结果为全0
c = a ^ b => a ^ c = a ^ a ^ b => a ^ c = b , => b ^ c = a // 交换两个数
指定位置的位运算
- 将x最右边的n位清零: x & (~0 << n)
// 0取反就是全部为1之后向左移n位了之后可以想象变为11111后面跟n个0 跟x与之后是指将x右边n位全部清零 - 获取x的第n位值(0或者1): (x >> n) & 1
// 把x先右移n次,那么x第n位就变成最后一位,然后再& 1就得到了第n位到底是0还是1 - 获取x的第n位的幂值: x & (1<< n)
// 把1往左移,移到高位,然后和x与之后 就是第n位的幂值 - 仅将第n位置为1: x | (1<< n)
- 仅将第n位置为0: x & (~(1<<n))
- 将x最高位至第n位(含)清零: x &((1<<n) -1)
实战位运算要点
判断奇偶数
x&2== 1 ⇒ (x & 1) == 1
x&2== 0 ⇒ (x & 1) == 0
x>>1 ⇒ x/2; //x右移一位,相等于把它的最后一位二进制位清空,整个数往右挪了一位,相等于除2
即x = x/2; ⇒ x = x>>1;
mid = (left + right) /2; ⇒ mid = (left + right) >>1;
X = X & (X-1) 清零最低位的1
X & -X ⇒ 得到最低位的1 // 注意这里不是~,而是取反
可知在计算机中数是以补码的形式储存的。
比如7,为111。-7为11111001。
其中求解-7的补码形式我们是怎么求解的呢?
负数原码转换为补码的方法之一:
符号位保持1不变,数值位按位求反,末位加1。
负数原码转换为补码的方法之二:
符号位保持1不变,在数值位中从低位向高位找1,第一个1及其右边的0保持不变,数值位的其余部分求反。
这两种方法大家试一试就会发现其实是一样的。
第一种方法是按照定义来设计的求解方式。
解释:一个正数的补码为原码自己,设为a,其负数形式的补码设为b,
可知a+b=0。方法一的求解方式就是先把这个数二进制中为0的哪些位给加上来,再加1,使得其进位,溢出为0.
如6=0000 0110,-6 = 1111 1001 + 1 = 1111 1010
可见最低位的1右边的0,在取反之后就会全部变为1,再加一,进位后,取反获取的1全部进位了,最低位的1又被进位上来了,即最低位的1保持不变。
方法二就是利用了这个性质,简化了求解过程中加1进位这一步.
于是我们可以利用补码正数和负数的这一点来快速求解一个数的最低位的1在哪里。
即n&-n
这样最低位的1被与运算保留下来,其他位全部置零。
X & ~X => 0
位运算的实战题目
剑指 Offer 15. 二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。
首先假设是32位的在java中
方法一 循环用一个for loop,从0到32,循环32次,每次先看第0位,再看第1位,再看第2位,
一直看到31位是否为二进制 的1,如果是二进制的1就count加1,不然的话就不加1
方法二 %2, /2, 先模2就看它最低位到底是否是1,然后再除以2,相等于把它最后一位打掉,最后看这个数是否为0,为0结束
方法三 &1, x = x>>1;上面的办法都要循环次数32位
方法四:while (x > 0) x = x& (x-1)清零最低位的1判断x是否为0,为0退出,循环次数不再是32次,而是有多少个1就循环多少次
- 2的幂
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 2^0 = 1
示例 2:
输入: 16
输出: true
解释: 2^4 = 16
示例 3:
输入: 218
输出: false
思想:一句话总结是否是2的幂次,这个数它的二进制表示形式里面有且仅有一个二进制位是1
首先n必须大于0,如果n==0,就没什么说的
return (n > 0) & (n & (n - 1)) == 0 或者 return (n != 0) & (n & (n - 1)) == 0
- 颠倒给定32位无符号整数的二进制位
方法一: int —> “010101” string -->reverse --> int
因为把Int转为二进制且是String的形式来表示,然后在reverse再转换成int,巨慢无比,且不符合计算机高效运算法则
方法二:位运算,写for循环把每一位拿出来如果是第1位,就移动到第32位,第i位就移动到第32-i位置上
var reverseBits = function(n) {
let ans = 0
for (let i = 0; i < 32; i++) {
ans = (ans << 1) + (n & 1)
n >>=1
}
return ans >>> 0
}