本章主要介绍如何用操作符进行解题(๑´ㅂ`๑)
目录
3.一个数组中只有两个数字是出现一次,其他所有数字都出现了两次,写一个函数,找出这两个只出现一次的数字
1.求一个整数的二进制中1出现的个数
法一:
我们知道二进制的权值为2^(n-1),除以一个2^(n-1),小数点向前移动n-1位,因此我们可以对一个二进制数进行连续相除一个权值(2),判断余数的方法来求得整数的二进制中1出现的个数。
下面是代码实现:
#include<stdio.h> int main() { size_t n = 0;//(此处用无符号整型才能对负数进行计算) int count = 0; scanf("%zu", &n); while (n) { if (n % 2 == 1) { count++; } n /= 2; } printf("%d", count); return 0; }
法二:
第二种方法就要用到操作符啦,在操作符中,>>操作符可以改变数的二进制位的最低位,而&1能得到数的二进制位的最低位,因此可以通过循环>>和&1的方法整数的二进制中1出现的个数。
下面是代码实现:
#include<stdio.h> int main() { int n = 0, count = 0; scanf("%d", &n); for (int i = 0; i < 32; i++) { if ((n >> i) & 1 == 1) { count++; } } printf("%d",count); return 0; }
法三:
方法三用到一个结论:n&(n-1)可以得到一个去掉n的二进制数的最低位的数
代码实现如下:
#include<stdio.h> int main() { int n = 0, count = 0; scanf("%d", &n); while (n) { n = n & (n - 1); count++; } printf("%d", count); return 0; }
2.求两个数的二进制中不同位的个数
可以将两个数异或起来,再求异或后数的二进制中一的个数
代码实现如下:
#include<stdio.h> int main() { int n1 = 0, n2 = 0, count = 0; scanf("%d %d", &n1, &n2); int n = n1 ^ n2; while (n & (n - 1)) { count++; } printf("%d", count); return 0; }
3.一个数组中只有两个数字是出现一次,其他所有数字都出现了两次,写一个函数,找出这两个只出现一次的数字
我们已经知道异或满足交换律,a^a=0,因此将数组中所用数字异或在一起可以得到两个只出现因此的数字,再找到异或后数的二进制中最低位1是第n位,根据数组中数的二进制位是否位1将数组分成两批(使只出现一次的数分进不同组里),每组当独异或即可得到两个只出现一次的数字
代码实现如下:
void findTwoNum(int arr[], int n, int* pnum1, int* pnum2) { int i; int sum = 0; for (i = 0; i < 9; i++) { sum ^= arr[i]; } //先找到两个数互相异或的结果 int pos; for (i = 0; i < 32; i++) { if (sum & 1 << i) { pos = i; break; } } //再找到有分歧的一位。在这一位上,两个数一定是一个1一个0 * pnum1 = *pnum2 = 0; for (i = 0; i < 10; i++) { if (arr[i] & 1 << pos) { *pnum1 ^= arr[i]; //这一位是1的,放在数1里 } else { *pnum2 ^= arr[i]; //这一位是0的,放在数2里 } } }
4.写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换
交换奇数位和偶数位可以分别拿出奇偶位再移位相加(奇数位拿出,那就是要&上010101010101……(0x55555555),偶数位拿出,就是要&上101010101010……(0xaaaaaaa) )
代码实现如下:
#define(SwapIntBit(n) (((n) & 0x55555555) << 1 | ((n) & 0xaaaaaaaa) >> 1)