【算法通关村】位移的妙用

文章介绍了两种计算二进制中1的个数(HammingWeight)的方法,一种是逐位判断,另一种是利用位运算的技巧。还讨论了如何颠倒二进制位数的两种方式,包括逐位操作和位运算分治法,以及它们在实际项目中的应用,如JDK和Dubbo协议解析。
摘要由CSDN通过智能技术生成

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;
     }
 };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值