有关异或的题目

有关异或的题目

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");
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值