zoukankan      html  css  js  c++  java
  • 如何理解x&(-x), x&(x-1) ?

    算法题里面,涉及到按位运算,有2个经典位运算:

    1. x&(-x) : 保留二进制下最后出现1的位置的数字,其余位置置0;
    2. x&(x-1) : 清除二进制下最后出现1的位置的数字,其余位置保持不变;

    x可以将二进制数写作(A) 1 (B)的形式,其中A表示一系列01串,1表示从右向左出现的第一个数字1,B表示空串(x是奇数)或者全0串(x是偶数)。那么,
    x是奇数时,x = (A) 1
    x是偶数时,x = (A) 1 (0..0)

    对于x&(-x)

    推演

    1)先求-x,
    -x代表x的相反数,在计算机中存储的是补码,也就是说,-x实际存储的是x反码 + 1
    x是奇数时,-x = (~A) 0 + 1 = (~A) 1
    x是偶数时,-x = (~A) 0 (1..1) + 1 = (~A) 1 (0..0)

    2)再求x&(-x),
    x是奇数时,x&(-x) = (0..0) 1
    x是偶数时,x&(-x) = (0..0) 1 (0..0)
    其中,1右边的0位数保持不变。也就是说x&(-x) 会保留二进制最右边出现的1位置对于数字,其余位置置0。

    应用

    求非负整数x能被2的n次幂整除的n最大值。
    考虑:
    如果x为奇数,∵x无法被2整除,只能被1整除 ∴n=0
    如果x为偶数,∵整除一个2的n次幂数,相当于右移n位
    ∴要求n的最大值,等价于求x最多能右移位数保持位1个数不变的移动数量 <=> 求x最右边连续0的个数

    如8 = 1000b,右移3位1个数不变,右移4位1的个数减少,而8最大能被2^3整除。
    24 = 1 1000b,右移3位1个数不变,右移4位1个数减少,而24最大能被2^3整除。
    故只需要保留最右边的1即可,因为只需要计算最右边连续0的个数。

    #include <stdio.h>
    
    int maxPowerOfTwo(int d) {
          d = d&(-d);
          int num = 0;
    
          while(d) {
                num ++;
                d = d >> 1;
          }
    	
          return num-1;
    }
    
    int main(void) {
          int n = maxPowerOfTwo(24);
          printf("%d
    ", n);
          return 0;
    }
    

    对于x&(x-1)

    推演

    1)先求x-1,
    x是奇数时,x-1 = (A) 0
    x是偶数时,x-1 = (A) 0 (1..1)

    2)再求x&(x-1)
    x是奇数时,x&(x-1) = (A) 0
    x是偶数时,x&(x-1) = (A) 0 (0..0)
    其中,原来1(现在的0)右边的位数保持不变。

    应用

    示例1:求32位整型数d对应二进制数包含的1的个数。

    #include <stdio.h>
    
    // 求二进制数d包含1的位数
    int countBitOne(int d) {
          int num = 0;
          while(d)
          {
                num++;
                d = d & (d-1);
          }
          
          return num;
    }
    
    int main(void) {
          int d = 0b101000;
          int nums = countBitOne(d);
          printf("%d
    ", nums);
          return 0;
    }
    

    示例2:判断一个数是否为2的n次方。
    思路:
    2的n次方是形如1,2,4,8,16,32,...这样的数
    1 -- 1b
    2 -- 10b
    4 -- 100b
    8 -- 1000b
    16 - 10000b
    32 - 100000b
    ...
    这样数的特点是二进制数据只包含1个位1,如果能将唯一的1清除,则必为0。考虑使用x&(x-1)将二进制数最后一位1清除。

    #include <stdio.h>
    #include <stdint.h>
    
    bool isTwoPower(int d) {
          if (d&(d-1) == 0) {
                return true;
          }
          return false;
    }
    

    推论

    1. x - x&(-x) = x&(x-1)
      左边式子表示在二进制数x基础上,清除最右边为1的数,与右边式子含义一样。

    REF

    https://www.cnblogs.com/yzxag/p/12668034.html

  • 相关阅读:
    Megcup 2017 决赛第一题 规则
    折正方体-------------给你出道题
    论公平
    Vue 将一个组件嵌入到另一个组件中
    Vue下的index.html
    Vue下的package.json
    Vue 一些用法
    chkconfig 系统服务管理
    Windows和Linux下的 telnet命令 不是内部或外部命令的解决方案
    JSONPlaceholder
  • 原文地址:https://www.cnblogs.com/fortunely/p/14119264.html
Copyright © 2011-2022 走看看