位运算常用运算
位操作是一种速度非常快的基本运算:有左移、右移、与、或、非、异或等运算。
左移:左移一位,相当于某数乘以2,比如110左移1位变为1100 ,右边的空位补0,6变为12,表示为(110<<1)
因此左移x位,相当于该数乘以2x
在右移时,需要注意符号位问题。对无符号数,右移时左边高位移入0。对于有符号的值,如果原来符号位为0(该数为正),则左边也是移入0,如果上例表示的那样,如果符号位原来为 1(该数为 负),则左边移入的 0还是1,要取决于所用的计算机系统。移入0 称为 逻辑右移,即简单右移。移入1称为算术右移。
右移:右移一位,相当于某数除以2,比如110右移1位变为011,6变为3,表示为(110>>1)
因此右移x位,相当于该数除以2x。
与运算:按位进行“与”运算,两数同一位都为1时结果为1,否则为0。例如:101&110=100。
或运算:按位进行“或”运算,两数同一位都为0时结果为0,否则为1。例如:101|110=11l。
非运算:按位取反。例如~101=010。
“异或”运算符(^) 它的规则是:若参加运算的两个二进制位值相同则为0,否则为1.
常见用法:反转二进制,只需要将想要反转的位异或1就可以, 如:1010^1111=0101
位运算实用”杀招“
若当前二进制位为S,对S有下列操作。
①判断第i位是否为0:(S&(1<<i)==0,意思是将1左移i位与S进行与运算后,看结果是否为0
②将第i位设置为1:S|(1<<i),意思是将1左移i位与S进行或运算。
③将第i位设置为0:S&~(1<<i),意思是S与第i位为0,其余位为1的数进行与运算。
例如:S=1010101,i=5。注意二进制位从0开始计数,所以i=5实际上是第6位
S&(1<<i):1010101&0100000=000000
课堂练习:
一个奇数次
输入一个长度为n的数组,考虑所有不同的数字,有且只有一个数字出现了奇数次。 比如对于1 2 3 1 2 3 1,我们考虑所有不同的数字1 2 3,有且只有1出现了奇数次(3次) 输出这个出现了奇数次的数字。 1 <= n <= 100000 1 <= a[i] <= 10^9
输入格式
第一行一个整数n, 接下来一行n个整数,表示输入的数字。
输出格式 一行一个数字,表示出现了奇数次的数字。
输入样例7
1
2
3
1
2
3
1
输出样例1
[解题思路]
一个比较简单的思路,对数组排序,然后逐个统计每个数字出现的次数,复杂度O(nlogn) 。
位运算异或^: 根据 XOR运算的性质,a ^ a=0 。如果某个数出现了两次,那么他们 异或在一起的值恰好为0。
进一步扩展,出现偶数次的数异或和也一定为0,出现奇数次的数异或和一定是这个数本身。因此只要将所有数异或 在一起,剩下的那个数就是出现奇数次的数。
#include<bits/stdc++.h> using namespace std;
int n;
int main() {
int x;
while (~scanf("%d", &n)) { int ans = 0;
for (int i = 0; i < n; i++) { scanf("%d", &x);
ans ^= x;
}
printf("%d\n", ans);
}
return 0;
}