lc191位1的个数
方式一:遍历每一位,判断是不是1,统计1出现的个数。用&和左移或右移判断。
public int hammingWeight(int n) { int cnt=0; for(int i=0;i<32;i++){ cnt += (n>>i)&1; } return cnt; }
⭐方式二:利用n&(n-1)可以将最后一个1变成0,统计1的个数。效率高。
public int hammingWeight(int n) { int cnt=0; while(n!=0){ n=n&(n-1); cnt++; } return cnt; }
lc338计算比特数
比特数即二进制中1的个数。
自己写的犯了个大错误!!
x每次被干成0,又+1循环,又干成0。
for循环嵌套while循环的经典错误。
public int[] countBits(int n) { int[] ans = new int[n+1]; for(int x=0;x<=n;x++){ int cnt=0; int i=x; //`要加临时变量记录下x的值 while(i>0){ i&=(i-1); cnt++; } ans[x]=cnt; } return ans; }
class Solution { public int[] countBits(int n) { int[] bits = new int[n + 1]; for (int i = 0; i <= n; i++) { bits[i] = countOnes(i); } return bits; } public int countOnes(int x) { int ones = 0; while (x > 0) { x &= (x - 1); ones++; } return ones; } }
lc190颠倒二进制位数
方法一:逐位颠倒
n&1即取出n二进制的最后一位。1是0000000…00001不是11111111111
0000 0010 1001 0100 0001 1110 1001 1100 &1 -> 0 <<31 0*** **** **** **** **** **** **** **** reversed+=0 n>>>1 0000 0001 0100 1010 0000 1111 0100 1110 &1 -> 0 <<30 00** **** **** **** **** **** **** **** reversed+=0 n>>>1 0000 0000 1010 0101 0000 0111 1010 0111 &1 -> 1 <<29 001* **** **** **** **** **** **** **** reversed+= 2^29 n>>>1 0000 0000 1010 0101 0000 0111 1010 0111
public class Solution { // you need treat n as an unsigned value public int reverseBits(int n) { int reversed=0,power=31; while(n!=0){ reversed += (n&1)<<power; n>>>=1; power--; } return reversed; } }
方式二:位运算分治
类似归并排序。
均分均分均分,翻转翻转翻转,合并合并合并。
对于递归的最底层,我们需要交换所有奇偶位。
这种方法在JDK,Dubbo等源码中都能见到,特别是涉及协议解析的场景,几乎都少不了位操作。
class Solution { private: const uint32_t M1 = 0x55555555; // 01010101010101010101010101010101 const uint32_t M2 = 0x33333333; // 00110011001100110011001100110011 const uint32_t M4 = 0x0f0f0f0f; // 00001111000011110000111100001111 const uint32_t M8 = 0x00ff00ff; // 00000000111111110000000011111111 public: uint32_t reverseBits(uint32_t n) { n = n >> 1 & M1 | (n & M1) << 1; n = n >> 2 & M2 | (n & M2) << 2; n = n >> 4 & M4 | (n & M4) << 4; n = n >> 8 & M8 | (n & M8) << 8; return n >> 16 | n << 16; } };