C语言之找单身狗

个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客

题目:

在一个整型数组中,只有一个数字出现一次,其他数组都是成对出现的,请找出那个只出现一次的数字。

例如:

数组中有:1 2 3 4 5 1 2 3 4,只有5出现一次,其他数字都出现2次,找出5

这个题目说难也难,说容易也容易,主要是看能不能想到。这个题目是让我们在相同中找不同(只有5是出现一次,其他数字都出现2次,找出5),就可以想到一个操作符按位异或(^),同为0,异为1 。不过这里有一个知识点:0 ^ n = n n ^ n = 0。这个题目在下面这篇文章中讲过,可以去看看。

利用操作符解题的精彩瞬间-CSDN博客

题目:

一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。

编写一个函数找出这两个只出现一次的数字。

例如:

有数组的元素是:1,2,3,4,5,1,2,3,4,6

只有5和6只出现1次,要找出5和6.

如果我们还用异或的方法,就会发现这个结果不是我们想要的。但是这个思想还是用异或的方法。因为这个题目还是找不同,只不过是多了一个数,并且要全部输出。但是如果我们把这个数组分为两个数组,每个数组中都只有一个数出现一次,然后再用上面的方法:异或 ,得出结果,分别输出。我们现在就是要找到这个分组的依据,如果根据这个例子,我们就会发现可以用奇偶的方法把这两个不同的数个分开。

复制代码
#include <stdio.h>
void FindNum(int* p, int sz)
{
	int num1 = 0;
	int num2 = 0;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		if (*(p+i) % 2 == 1)
		{
			num1 ^= *(p + i);
		}
		else
		{
			num2 ^= *(p + i);
		}
	}
	printf("%d %d\n", num1, num2);
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	FindNum(arr, sz);
	return 0;
}

当然这个方法有局限性,只限于这两个出现一次的数,一个是奇数一个是偶数。如果两个都是奇数或者偶数不行。

这里还是用异或,将这个数组中的数全部异或到一起,把最终的结果转化为二进制。看看二进制中的1,随机选一个1,作为异或的结果。画图演示:

我们把倒数第二位的1作为分界限。把这个位是1的分成一组,是0的分成1组。当然这里可能会有小伙伴有疑惑:这个1,只是把5和6分开了,但是那些其它的数字呢?其实这里我们的目的从一开始就是要把5和6分开就行了。因为那些数都是一对的,不管是前面的奇偶性,还是二进制位都是一样的,我们分开了一个,另外一个也会跟着走。

cs 复制代码
#include <stdio.h>
void FindNum(int* p, int sz)
{
	//第一步把全部的数异或到一起,得出最终的结果
	int ret = 0;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= *(p + i);
	}
	//将ret的一个二进制位1,作为分界线,1是一组,0是一组
	int num1 = 0;
	int num2 = 0;
	for (i = 0; i < sz; i++)
	{
		//ret >> 1就是把倒数第二位的二进制位移到倒数第一位(只有这样才能判断是否为1)
		//(*(p + i))) >> 1 就是和上面一样的效果。
		if( ((ret >> 1) & ((*(p + i))) >> 1 )== 1)
		{
			num1 ^= *(p + i);
		}
		else
		{
			num2 ^= *(p + i);
		}
	}
	printf("%d\n", num1);
	printf("%d\n", num2);
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	FindNum(arr, sz);
	return 0;
}

但是这个代码也是有缺陷的,只能把倒数第二位的找出(就像5和6)。如果要推广的话,就不可以,除非我们把那个异或的数的第K位为1找出来,移到想要的位数来比较。得到K的值

cs 复制代码
#include <stdio.h>
void FindNum(int* p, int sz)
{
	//第一步把全部的数异或到一起,得出最终的结果
	int ret = 0;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= *(p + i);
	}
	//将ret的一个二进制位1,作为分界线,1是一组,0是一组
	//接下来就是找这个1。
	int k = 0;
	for (i = 0; i < 32; i++)//最坏的结果就是找32次
	{
		if (((ret >> i) & 1) == 1)//最低位为1,则说明是1
		{
			k = i;
			break;
		}
	}
	int num1 = 0;
	int num2 = 0;
	for (i = 0; i < sz; i++)
	{
		//i >> k就是把i的二进制位移了k位,看看与1的结果,如果是1,则说明该位是1
		if( (((*(p + i)) >> k) & 1) == 1)
		{
			num1 ^= *(p + i);
		}
		else
		{
			num2 ^= *(p + i);
		}
	}
	printf("%d\n", num1);
	printf("%d\n", num2);
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	FindNum(arr, sz);
	return 0;
}

这里就是可以任意找了。注意一下:在判断数组元素与1的结果是否为1时,要把括号加上去,阐明优先运算。

相关推荐
Python×CATIA工业智造43 分钟前
详细页智能解析算法:洞悉海量页面数据的核心技术
爬虫·算法·pycharm
无聊的小坏坏2 小时前
力扣 239 题:滑动窗口最大值的两种高效解法
c++·算法·leetcode
黎明smaly2 小时前
【排序】插入排序
c语言·开发语言·数据结构·c++·算法·排序算法
YuTaoShao2 小时前
【LeetCode 热题 100】206. 反转链表——(解法一)值翻转
算法·leetcode·链表
YuTaoShao2 小时前
【LeetCode 热题 100】142. 环形链表 II——快慢指针
java·算法·leetcode·链表
CCF_NOI.2 小时前
(普及−)B3629 吃冰棍——二分/模拟
数据结构·c++·算法
运器1233 小时前
【一起来学AI大模型】支持向量机(SVM):核心算法深度解析
大数据·人工智能·算法·机器学习·支持向量机·ai·ai编程
Zedthm3 小时前
LeetCode1004. 最大连续1的个数 III
java·算法·leetcode
LIN-JUN-WEI3 小时前
[ESP32]VSCODE+ESP-IDF环境搭建及blink例程尝试(win10 win11均配置成功)
c语言·开发语言·ide·vscode·单片机·学习·编辑器
神的孩子都在歌唱3 小时前
3423. 循环数组中相邻元素的最大差值 — day97
java·数据结构·算法