有关异或的题目
1.有101个整数,其中有50个数出现了两次,1个数出现了1次,找出出现了一次的那个数。
异或:相同数字得到0,任何数与零异或,最终得到自身,同时异或满足交换律。
# include<stdlib.h>
# include<stdio.h>
int main() {
int a[13] = { 1,2,3,4,5,6,17,1,2,3,4,5,6 };
int result = 0;
for (int j = 0; j <= sizeof(a)/4 - 1;++j) {
result ^= a[j];
}
printf("%d",result);
}
2.有102个整数,其中有50个数出现了两次,2个数出现了一次,找出出现了一次的那两个数。
首先将所有的数异或,因为有两个数出现一次,所以最终得到的异或结果,实际上是两个出现一次的数的异或结果,由最低位为1可以得知,出现一次的两个数的这一位一定不同,因些拿到该与所有的数按位与,为1的放在一堆,为0的放在另一堆,为0的放在另一堆,就能将两个出现一次的数分开,然后对两堆各自异或,就能找到出现一次的两个数。
PS:一个数与自身的相反数进行异或到得这个数的最低位的1
# include<stdlib.h>
# include<stdio.h>
int main() {
int arr[10] = { 1,1,2,2,3,3,4,4,99,100 };
int result0 = 0;
int result1 = 0;
int n = 0;
for (int j = 0; j < sizeof(arr) / sizeof(int);++j) {
n ^= arr[j];
}
n = n & (-1 * n);//找到两个只出现一次数的异或值的最低位的1
for (int j = 0; j < sizeof(arr) / sizeof(int); ++j) {
if (n & arr[j]) {
result0 ^= arr[j];
}
else {
result1 ^= arr[j];
}
}
printf("%d %d ",result0,result1);
}
3.有103个整数,其中有50个数出现了两次,3个数只出现一次,找出出现了一次的三个数。
由于3个数字出现一次,其他数字均出现两次,因此可以得到n一定为奇数。
3个只出现一次的数字,它们的bit位,肯定不可以全部相同,也就是说,虽然有些bit位上的数可能相等,但肯定至少存在某个bit位,在这3个数中,有两个数的该bit位为1,一个数的该bit为0,或者两个数的该bit位为0,一个数的该bit位为1。
我们可以通过扫描int的所有bi位,扫瞄每个bit位时,遍历数组,如果能找出符合上面条件的,就可以找出其中一个只出现一次的数字,该数字与另外两个只出现一次的数的bit位不同。通过bit位不同分成两堆,对每堆进行异或,如果异或结果表明两堆均不为零,那么说明分开了,偶数个数的那堆有两个数,奇数个数的那堆有一个数。
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
#define N 9
void findTwoNum(int* arr, int result,int first) {
int split = 0,i;
int find1 = 0, find2 = 0;
split = result & -result;
for (i = 0; i < N;++i) {
if (split&arr[i]) {
find1 ^= arr[i];
}
else {
find2 ^= arr[i];
}
}
if (split&first) {
find1 ^= first;
}
else {
find2 ^= first;
}
printf("find2=%d,find3=%d",find1,find2);
}
int main() {
int arr[N] = {8,11,20,7,11,20,9,8,5};
int heapResult1, heapResult2;
int heapCount1,heapCount2;//每一堆元素的数目
int split = 1,i,j;
for (j = 0; j < 32;++j) {
//每次循环都要把heapCount和heapResult置0
heapCount1 = heapCount2 = 0;
heapResult1 = heapResult2 = 0;
split = split << j;
for (i = 0; i < N; i++) {
if (split & arr[i]) {
heapCount1++;
heapResult1 ^= arr[i];
}
else {
heapCount2++;
heapResult2 ^= arr[i];
}
}
//分堆完成后再进行判断是否是有效的分堆
if (heapCount1 % 2 == 0 && heapResult1 != 0) {
printf("find1=%d\n", heapResult2);
findTwoNum(arr, heapResult1, heapResult2);
break;
}
if (heapCount2 % 2 == 0 && heapResult2 != 0) {
printf("find1=%d\n", heapResult1);
findTwoNum(arr, heapResult2, heapResult1);
break;
}
}
}
二级指针
# include<stdio.h>
# include<stdlib.h>
void change(int **pa, int *pb) {
*pa = pb;
}
//在子函数需要修改主函数内某个一级指针,需要二级指针
int main() {
int i = 10, j = 5;
int *pi, *pj;
pi = &i;
pj = &j;
printf("i=%d,j=%d,*pi=%d,*pj=%d\n",i,j,*pi,*pj);
change(&pi, pj);
printf("i=%d,j=%d,*pi=%d,*pj=%d\n", i, j, *pi, *pj);
system("pause");
}
二级指针的偏移
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
#define N 5
void print(char (*p)[10]) {
int i;
for (i = 0; i < N; ++i) {
puts(p[i]);
}
}
void printPointerArr(char **p) {
int i;
for (i = 0; i < N;++i) {
puts(p[i]);
}
}
//二级指针的初始化是某个一级指针变量取地址
int main() {
int *pArr[N];
char b[N][10] = {"lele","lili","lilei","hanmeimei","zhousi" };
int i, j;
int *pTmp;
char **p2=(char **)malloc(sizeof(char*)*N);//
for (i = 0; i < N; ++i) {
p2[i] = b[i];
}
print(b);
for (i = N; i > 1;i--) {
for (j = 0; j < i - 1; j++) {
if (strcmp(p2[j], p2[j+1])>0) {
pTmp = p2[j];
p2[j] = p2[j + 1];
p2[j + 1] = pTmp;
}
}
}
printf("------------------------------------\n");
printPointerArr(p2);
printf("------------------------------------\n");
print(b);
system("pause");
}
函数指针
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
void b() {
printf("I am b func\n");
}
void a(void (*p)()) {
p();
}
int main(){
void (*p)();//p函数指针
a(b);
system("pause");
}