力扣260.只出现一次的数字|||(C语言)

目录

题目概述:

题目解读:

异或(^)原理:

全局代码:

步骤分析:

                 


题目概述:

题目解读:

题目对时间效率和空间效率都有要求,但空间要求可视为空气,线性时间复杂度即为o(n)。

基本思路;

(1)暴力美学解法:

直接采用排序的方法,对nums数组进行由小到大,再创建一个0~n的完整的数组,再去和nums数字一一对比,就可以找到只出现一次的两个元素,在无限制的情况下不失为一种好方法,但题目要求为o(n),此方法就不合格,所以就不多bb了。

(2)奇淫巧计解法:

采用异或(^)解题,用z=0去异或nums数组的每一个数,此时得到两个解的异或值,要将其分离开,所以去找到二进制z的首位(从右向左)不为零的数(也可以是任何一个位,不影响结果),假设z的第3位为1,就把第3位是否为1为条件把nums数组分为两组,每组异或到一起,这样每组的结果就是所要求解的两个数,接下来,围绕此思路细细展开。

异或(^)原理:

小小的(^)符号,除了在一些计算题中,好像再也没有见过他的身影,但是在此类题目中却是“关键先生”,用0去异或一个数,数值不变(0^5=5),同一个数异或两次为0(5^5=0),而且不用连续异或相同的数才会抵消,可以不在意顺序。

全局代码:

int* singleNumber(int* nums, int numsSize, int* returnSize)
{
	int z=0;
	for(int i=0;i<numsSize;i++)
	{
		z^=nums[i];
	}
	long tmp=1;
	int m=0;
	while(1)
	{
		if(z&(tmp<<m))
		break;
		else
		++m;
	}
//	while(!(z&tmp))
//	{
//		tmp<<1;
//		
//	}
	int x=0,y=0;//用来保存两个解 
	for(int i=0;i<numsSize;++i)
	{
		if(nums[i]&(tmp<<m))
		{
			x^=nums[i];
		}
		else
		y^=nums[i];
	}
	*returnSize=2;
	int *p=(int*)malloc(sizeof(int)*2);
	p[0]=x;
	p[1]=y;
	return p; 
	
}

 

步骤分析:

以提供的案例一为例;

(1)

int z=0;
	for(int i=0;i<numsSize;i++)
	{
		z^=nums[i];
	}

定义一个整型的变量z,然后循环去异或数组的数值,得到z=3^5,然后去分离3和5。

(2)

long tmp=1;
	int m=0;
	while(1)
	{
		if(z&(tmp<<m))
		break;
		else
		++m;
	}

看到长整型,就有小伙伴要质疑博主是个笨比了,其实不然,有个非常恶心的测试案例,如果不设置为长整型的话,再下边的位运算会越界的。

通过一个循环找到了(3^5)首位为1的位置(其实可以是任意位置为1,不影响结果),然后以此为条件去分组。

(3)

	int x=0,y=0;//用来保存两个解 
	for(int i=0;i<numsSize;++i)
	{
		if(nums[i]&(tmp<<m))
		{
			x^=nums[i];
		}
		else
		y^=nums[i];
	}

 按照第m位为1和为0为条件,分为两组,相同的数会分到同一组然后异或相互抵消掉,酱紫,x和y就是求得的解。

(4)

	*returnSize=2;
	int *p=(int*)malloc(sizeof(int)*2);
	p[0]=x;
	p[1]=y;
	return p; 

这个题还有个小bug(苦笑),提供了一个多余的参数 int* returnSize,这是个用来返回解的数量的,题目已经说是两个了,还要这个参数,不是脱了裤子放屁唛?

看这里!

其实还有一个小性质,可以省略一些位运算,可运用到第(2)步

z=z&(-z);

z与-z进行与预算,可以直接得到(3^5)首位为一的位置(说位置不太准确,相当于得到将1位移到首位为1的地方的数值,

 可以看到得到是相同的结果,这样无需定义长整型变量tmp,但要注意后方代码变动!

最后的最后:

这类题在力扣有个1,2,3个题目,此为第三题,还有一个较为简单的父类题,17.04消失的数字,用来加强练习。

做算法题,要多学习和总结方法,然后疯疯癫癫的去刷题升级,如果能写一篇文章能更好的掌握技巧。

勿喷,如果有错误或模棱两可的地方,请一定要不吝啬的指出,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客1号

感谢老板,老板大气!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值