当前位置: 首页 > article >正文

剑指 Offer 56 - I. 数组中数字出现的次数

理想的人物不仅要在物质需要的满足上,还要在精神旨趣的满足上得到表现。        —— 黑格尔

目录

方法1:排序+指针

方法2:异或整个数组

题目:

一个整型数组 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]

 

做题链接:剑指 Offer 56 - I. 数组中数字出现的次数

方法1:排序+指针

假如数组中的数字是:1,2,10,4,1,4,3,3。我们将这些数字进行排序,排序之后为1,1,2,3,3,4,4,10。我们的目标就是找出没有重复出现的两个数字,也就是2和10。

我们使用一个指针指向排序好数组的最后一个位置。
1.
然后看这个位置的数字和前一个位置的数字相不相等。如果相等,也就是没有找到我们的目标数字,然后指针向前移动两个位置,继续找,以此类推。

2.如果最后一个位置和前一个位置不相等,那么此时的最后一个位置也就是我们找到的第一个目标数字。然后指针向前移动一位,继续找前面的数字。

那么上述的话是什么意思呢?我们使用画图来理解。

理解上述的话之后,我们直接上手写代码:

#include<stdlib.h>
int cmp_int(void* p1, void* p2)
{
	return *(int*)p1 - *(int*)p2;
}
int main()
{
	int arr[10] = { 0 };
	int n = 0;
	scanf("%d", &n);
	int i = 0;
	for (i = 0; i < n; i++)
	{
		scanf("%d", &arr[i]);
	}
	qsort(arr, n, sizeof(int), cmp_int);//这里使用快排的进行排序
	int right = n - 1;
	int j = 0;
	int k = 0;
	while (right > 0)
	{
		if (arr[right] != arr[right - 1])
		{//这里不相等,则找到了,直接打印出来
			printf("%d ", arr[right]);
			if (right == 1)
			{
				printf("%d", arr[0]);
			}
			right -= 1;//所以right-1,指向下一个位置
		}
		else
		{
			right -= 2;//否则right-2,指向下两个位置
		}
	}
	return 0;
}
if (right == 1)
{
 printf("%d", arr[0]);
}

这个代码如何理解呢?我们举个例子来讲解一下。
如果我们排序好的数组是 1 ,2,5,5,7,7,9,9。那么我们要找的数字就是1和2, 此时right指向的就是2,然后2和前面的1比较,显然2和1不相等,那么2就是我们要找到的数字。

然后right向前移动一位,指向1,然后1再和前面的数字进行比较,但是1前面没数字了,那么退出循环。但是1没有打印出来呀,所以我们单独打印第一个数字。这就是这个代码的意思。


 

方法2:异或整个数组

异或的计算法则是:二进制相同为0,不同为1。

有一个找单身狗的题:数组中其他数字均出现两次,有一个数字出现了一次,我们的目标就是找这个出现一次的数字,我们就可以使用异或全部的数字,得到的答案就是我们要找的数字,因为相同的数字异或为0,0和目标数字异或得到目标数字。

做题方法:这题我们一样可以使用异或整个数组来实现。相同的数字异或为0,最后的异或结果就是两个目标数字异或的结果。假如数组为1,2,10,4,1,4,3,3。

废话不多说,直接上代码:

int* singleNumbers(int* nums, int numsSize, int* returnSize) {
	int* ans = (int*)calloc(2, sizeof(int));//calloc开辟的空间会自动赋值为0
	int temp = 0;
	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		temp ^= nums[i];//temp就是两个目标数字异或的结果
	}
	int pos = 0;//记录位置
	for (i = 0; i < 32; i++)
	{
		if (((temp >> i) & 1) == 1)//找二进制第一个1的位置
		{
			pos = i;
			break;
		}
	}
	//分组异或
	for (i = 0; i < numsSize; i++)
	{
		if (((nums[i] >> pos) & 1) == 1)
		{
			ans[0] ^= nums[i];
		}
		else
			ans[1] ^= nums[i];
	}
	*returnSize = 2;
	return ans;
}

 

希望能对你有所帮助,感谢你的支持。 

 


http://www.kler.cn/a/6355.html

相关文章:

  • SecureCRT汉化版
  • 谷歌集群数据集:负载均衡云服务测试数据
  • 《Vue3实战教程》5:响应式基础
  • Jenkins 任意文件读取(CVE-2024-23897)修复及复现
  • Flask中@app.route()的methods参数详解
  • 服务器证书原理
  • Android物理按键事件处理
  • springboot 数据库应用
  • .NET Core 中实现分布式事务的几种方案
  • 理想汽车的雷达在无人陵园内看到鬼?网友:按一下喇叭看会不会聚过来!
  • 基于SpringBoot开发的人事管理系统
  • Python 高级编程(文件操作)
  • TCP / IP 模型
  • AtCoder Beginner Contest 296 (A~D)
  • 虚拟机与主机互传文件
  • 【C++】哈希
  • C++初阶—string类(1)
  • web前端面试题之webpack和其他
  • spring七种事务传递机制及其原理
  • 会C#如何学习Python的几个关键点
  • pytorch安装和测试
  • MyBatis
  • 注册谷歌账户教程--解决注册谷歌账户“此电话号码无法用于进行验证”问题--亲测已解决--谷歌账户注册全流程
  • 【面试】Java并发编程面试题
  • XGBoost的简单安装及入门使用
  • Kubuntu(Ubuntu) 22.04安装OBS Studio