数组中数字出现的次数

力扣题:数组中数字出现的次数

这次写的博客很简单就是想分享一下写力扣题的一些思路,希望能对需要的人有点帮助呀。那么就让我们先来看看题目的要求(这是一道OJ题,只需要完成函数就行了)

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

在这里我先放一下我写的代码然后再去解释思路:

int* singleNumbers(int* nums, int numsSize, int* returnSize)
{
    int count1 = nums[0], count2 = 0, count3 = 0;
	int i = 0;
	for (i = 1; i<numsSize; i++)
	{
		count1 ^= nums[i];//count1代表两个单独的数按位与
	}
	count2 = count1;//count2是count1的拷贝,后面会改变值
	while (count2)
	{
		count3++;//计算二进制中第几位是1,那就在找的时候找相同位置是0的位置
		if (count2 % 2 == 1)
		{
			break;
		}
		count2 = count2 / 2;
	}
	count2 = count1;
	for (i = 0; i<numsSize; i++)//找nums数组里面符合的数
	{/*之所以是count3-1是因为移动的位数需要比总位数少1
	举个例子就好理解了,假如说count1的二进制中第一位就是1(这里是从右往左的第一位),
	那么我们去找的时候是不需要移位的因为是从第一位开始向后遍历*/
		if ((nums[i]>>(count3-1))&1 == 1)
		{
			//如果有符合条件的那么就直接和count2异或
			count2 ^= nums[i];
		}
	}
	int* ptr = (int*)malloc(2 * 4);
	*ptr = count2;
	count1 ^= count2;
	*(ptr + 1) = count1;
	*returnSize =2;
	return ptr;
}

那让我来解释下这段代码以及我做这题时的思路:当我们看到一个题目的时候有几件事情我感觉需要去做一下,首先看一下题目让我们干什么这是第一步需要我们去做的事情,然后就是去分析他给的这个函数的参数,OJ题的函数参数是干什么的不会在题目中明确告知,我们需要根据参数名来去分析我认为分析函数的参数是十分重要的,我就是因为一开始做这题的时候没有分析清楚出的错。就例如这一题它刚进入的时候给的函数以及参数就是:

int* singleNumbers(int* nums, int numsSize, int* returnSize){
}/*我们来一个一个的看参数,首先是int* nums我们根据示例可以得知的就是nums在主体函数中
是让我操作的数组,我们需要在这个数组里面去查找,然后是这个int numsSize这个根据单词,
nums是数组了,然后size是大小,我们就推测这个传的是数组的大小(也就是数组的元素个数)
再看看最后一个这个int* returnSize首先这个是一个int*型的我们可以推测它传的是地址然后
是return这个是返回,size是大小,就可以想到这个是记录返回的大小的,因为题目说这只有2个
数是单身数,所以其实在这基本上就能确定这个值是为2的,只需要在最后改一下就好*/

分析完了函数的参数,我们就需要开始对题目进行分析了,说到这里我们就再顺便一提,写这种编程题其实我感觉提前想好思路画好图,再根据思路去写代码,比看到题目就直接敲代码,想到哪是哪的那种做法要好不少,因为事先想好思路在编的时候会很丝滑,而且也方便出错后的检查。
那我们开始分析这个题目:首先题目说数组里面只有两个数是单身数,其他的数都是重复存在的,看到这里就想要怎么做才能够把重复的全去掉,只留下单身的数,或者只留下与单身的数有关的数,这时候就要想到一个位操作符异或(^)操作符,它就是两个数字的二进制位依次异或:同为0,异为1,知道这个性质之后,是不是就可以把数组里面的所有元素异或一下,这样得到的是不是就是两个单身的数异或的结果。得到这个结果之后我们要想的就是如何的到这两个数了?那我们就可以从这个异或之后的这个数做文章。
1
我们知道异或是同为0异为1,那么是不是异或之后的count1它的二进制中为1的那些位,两个单身的对应位上的数是不相同的,也就是说我们可以根据这一点来区分出来这俩个数,之后就有了两种做法:第一种是根据这点不同可以将两个数分到两个数组中去,然后每个数组中的元素进行异或,就可以分别得到这两个数(但是这样有一点不好就是需要创建新的数组,需要开辟新的空间,效率不是很高),在这里我选择的是第二种,不需要去开辟空间直接在原来的上面去改动。
下面我就来详细的说一下第二个思路:我用图来表示好说一点(用手绘板写的字有点丑请见谅)
2
上图就是第二种方法的思路,剩下的就是去实现这个思路了,可以参考这个代码,这个OJ题调用后会自己free并且把malloc或者calloc置空,所以不需要我们手动去置空。

这就是我写这题的思路,希望对大家有所帮助。

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值