刷题之:找数组中只出现一次的两个数

目录

题目:

函数实现思路

分离两个待查找的数

定位二进制为1的位数

全部代码实现


示例:

int arr[] = { 1,1,2,2,3,3,4,5,5,6,7,7,8,8,9,9 };
  • 题目:


在数据成对出现的数组中又两个数值只出现了一次,将这两个数值找出来。

思路

如上面的示例,我们需要将4,6这两个只出现一次的数值找到。明显过程较为复杂,我们采用函数包装。

函数设计

我们需要清楚函数的参数,返回类型是什么?

需要处理的是一个数组,采用指针/数组传参,传数组的元素个数;我们需要返回两个数,所以需要返回一个数组,即一个地址,采用整形指针类型。

int* singleNumber(int* arr, int numsSize)
  • 函数实现思路


异或解法:我们知道,使用异或解决只出现一个一次出现的数时,是十分简便的,所以只要将找两个出现一次的数值,转化为找一个出现一次的数值就好解决了。由此可以想到,需要将数据分为两个部分,两个出现一次的数值分别发布在两边,就转化为了求解两个找出现一次的数值的问题了。

  • 分离两个待查找的数


如何分离呢?

我们需要找到这两个数的不同之处,使用异或可以将这两个数区分开来。

 那么我们就可以根据这一特性将其分开,我们选取异或(^)后的二进制序列任意一位为1的位数。只要数组中元素对应的这二进制位为1的数值就分到一组,为0的分到另外一组。这里可以分析一下,最后分到两组的元素是怎么样的呢?

(有一个出现一次的数值,其余的都是成对出现的)

为什么是成对出现的呢?

刚刚提到有一位二进制位数相同的进入同一组,那么数值相同二进制序列也就相同,也就会进入同一组,只有两个只出现一次的数值才会被分开分别进入两组。

  • 定位二进制为1的位数


首先定位一个二进制位为1的位数m

    int x = 0;
	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		x ^= arr[i];//异或
	}
	int m = 0;
	//定位x二进制序列为1的位数
	for (i = 0; i < 32; i++)
	{
		if ((x >> i & 1) == 1)
		{
			m = i;
			break;
		}
	}

再将其分开

//将出现一次的两个数分开
	int x1 = 0;
	int x2 = 0;
	for (i = 0; i < numsSize; i++)
	{
		if ((arr[i] >> m & 1) == 1)
		{
			x1 ^= arr[i];//只有一个数值出现一次其余成对出现的全部被异或完了
		}
		else
		{
			x2 ^= arr[i];//只有一个数值出现一次其余成对出现的全部被异或完了
		}
	}

最后返回值就可以了

int* a = (int*)malloc(sizeof(int)*2);
	a[0] = x1;
	a[1] = x2;
	
	return a;
  • 全部代码实现



#include <stdio.h>
#include <stdlib.h>

int* singleNumber(int* arr, int numsSize)
{
	int x = 0;
	int i = 0;
	for (i = 0; i < numsSize; i++)
	{
		x ^= arr[i];//异或
	}
	int m = 0;
	//定位x二进制序列为1的位数
	for (i = 0; i < 32; i++)
	{
		if ((x >> i & 1) == 1)
		{
			m = i;
			break;
		}
	}
	
	//将出现一次的两个数分开
	int x1 = 0;
	int x2 = 0;
	for (i = 0; i < numsSize; i++)
	{
		if ((arr[i] >> m & 1) == 1)
		{
			x1 ^= arr[i];
		}
		else
		{
			x2 ^= arr[i];
		}
	}
	int* a = (int*)malloc(sizeof(int)*2);
	a[0] = x1;
	a[1] = x2;
	
	return a;
}
int main()
{
	int arr[] = { 1,1,2,2,3,3,4,5,5,6,7,7,8,8,9,9 };
	int len = sizeof(arr) / sizeof(int);
	int i = 0;
	int* pa = singleNumber(arr, len);
	for (i = 0; i < 2; i++)
	{
		printf("%d ",pa[i]);
	}
	free(pa);
	pa = NULL;

	return 0;
}

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
为了实现这个方法,我们可以使用层循环遍历数组中的每一个元素,并到满足条件的元素的下标。具体步骤如下: 1. 创建一个空字典,用于存储每个元素的值和下标。 2. 遍历数组nums,对于每个元素num,执行以下操作: - 计算目标值与当前元素的差值diff:diff = target - num。 - 检查diff是否在字典中,如果存在,则说明到了满足条件的元素,返回它们的索引:return [字典[diff], 当前元素的下标]。 - 如果diff不在字典中,则将当前元素的值和下标添加到字典中:字典[num] = 当前元素的下标。 3. 如果遍历完整个数组都没有到满足条件的元素,则说明不存在这样的组合,返回一个空列表。 下面是代码的实现: ```python def find_two_sum(nums, target): num_dict = {} for i, num in enumerate(nums): diff = target - num if diff in num_dict: return [num_dict = i return [] ``` 请注意,在这个方法中,我们使用了一个字典来存储每个元素的值和下标,这样可以快速查满足条件的元素的下标。如果到了满足条件的元素,我们直接返回它们的下标。如果遍历完整个数组都没有到满足条件的元素,则返回一个空列表。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [js代码-给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 个 ...](https://download.csdn.net/download/weixin_38720173/20324980)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 个 整数](https://blog.csdn.net/weixin_39924674/article/details/111014115)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

绅士·永

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值