📜  竞争编程的位技巧

📅  最后修改于: 2021-04-26 05:57:27             🧑  作者: Mango

在竞争性编程中或一般而言,某些问题似乎很困难,但只需一点点魔术就可以很容易地解决。我们在上一篇文章的下面讨论了一些技巧。

竞争编程的按位技巧

我们在本文中考虑了以下事实–

  • 基于0的从左到右的位索引。
  • 设置第i位意味着将第i位变为1
  • 清除第i位意味着将第i位变为0

1)从LSB清除所有位到第i位

mask = ~((1 << i+1 ) - 1);
x &= mask;

逻辑:要清除所有从LSB到第i位的位,我们必须使用具有LSB到第i位0的掩码与x进行“与”运算。要获得这样的掩码,请先左移1次i次。现在,如果我们从中减去1,则从0到i-1的所有位都将变为1,其余的位将变为0。现在,我们可以简单地对mask进行补码,以使所有前i个位均变为0并保持不变。
例子-
x = 29(00011101),我们想将LSB清除为第3位,共4位
面具-> 1 << 4-> 16(00010000)
遮罩-> 16 – 1-> 15(00001111)
面具->〜mask-> 11110000
x和遮罩-> 16(00010000)

2)将所有位从MSB清除到第i位

mask = (1 << i) - 1;
x &= mask;

逻辑:要清除所有从MSB到第i位的比特,我们必须使用具有MSB到第i个比特0的掩码对与x进行“与”运算。要获得这样的掩码,请先左移1次i次。现在,如果我们从中减去1,则从0到i-1的所有位都将变为1,其余的位将变为0。
例子-
x = 215(11010111),我们想将MSB清除为第4位,共4位
面具-> 1 << 4-> 16(00010000)
遮罩-> 16 – 1-> 15(00001111)
x和遮罩-> 7(00000111)

3)除以2

x >>= 1;

逻辑:当我们进行算术右移时,每个位都将右移,空白位置将替换为数字的符号位,如果是正数则为0,如果是负数则为1。由于每个位都是2的幂,所以每次移位时,我们都将每个位的值减小2倍,这相当于x除以2。
例子-
x = 18(00010010)
x >> 1 = 9(00001001)

4)乘以2

x <<= 1;

逻辑:当我们进行算术左移时,每个位都向左移,空白位置替换为0。由于每个位都是2的幂,所以每次移位时,我们都将每个位的值增加2倍,这相当于x乘以2。
例子-
x = 18(00010010)
x << 1 = 36(00100100)

5)大写英文字母到小写字母

ch |= ' ';

逻辑:大写和小写英文字母的位表示为–

A -> 01000001          a -> 01100001
B -> 01000010          b -> 01100010
C -> 01000011          c -> 01100011
  .                               .
  .                               .
Z -> 01011010          z -> 01111010

如我们所见,如果我们设置了大写字符的第5位,它将被转换为小写字符。我们必须准备一个具有第5位1和其他0(00100000)的掩码。此掩码是空格字符(”)的位表示形式。然后,字符“ ch”与掩码进行“或”运算。

例子-
ch =’A’(01000001)
遮罩=”(00100000)
ch |掩码=’a’(01100001)
有关详细信息,请参阅大小写转换(从低到高,从反之亦然)。

6)小写英文字母到大写

ch &= '_’ ;

逻辑:大写和小写英文字母的位表示为–

A -> 01000001                a -> 01100001
B -> 01000010                b -> 01100010
C -> 01000011                c -> 01100011
.                               .
.                               .
Z -> 01011010                z -> 01111010

如我们所见,如果清除了第5位小写字符,它将转换为大写字符。我们必须准备一个具有第5位0和其他1(10111111)的掩码。此掩码是下划线字符(’_’)的位表示形式。字符“ ch”然后与掩码进行“与”运算。
例子-
ch =’a’(01100001)
遮罩=’_’(11011111)
ch和mask =’A’(01000001)
有关详细信息,请参阅大小写转换(从低到高,从反之亦然)。

7)以整数计数设置位

int countSetBits(int x)
{
    int count = 0;
    while (x)
    {
        x &= (x-1);
        count++;
    }
    return count;
}

逻辑:这是Brian Kernighan的算法。

8)查找32位整数的日志基数2

int log2(int x)
{
    int res = 0;
    while (x >>= 1)
        res++;
    return res;
}

逻辑:我们反复右移x直到它变为0,同时我们继续依靠移位操作。此计数值为log2(x)。

9)检查给定的32位整数是否为2的幂

int isPowerof2(int x)
{
    return (x && !(x & x-1));
}

逻辑:2的所有幂仅设置一个位,例如16(00010000)。如果我们从中减去1,则从LSB到设置位的所有位都将被触发,即16-1 = 15(00001111)。现在,如果我们将x与(x-1)进行“与”运算,则结果为0,则可以说x是2的幂,否则就不是。当x = 0时,我们必须格外小心。

例子
x = 16(000100000)
x – 1 = 15(00001111)
x&(x-1)= 0
所以16是2的幂

请参阅本文以了解更多技巧。