三个数是唯一出现的,其余的都出现偶数个,找出这三个数中。

2024-05-03 23:48

本文主要是介绍三个数是唯一出现的,其余的都出现偶数个,找出这三个数中。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目:一个数组里,除了三个数是唯一出现的,其余的都出现偶数个,找出这三个数中。

比如数组元素为[1,1,2,2,3,3,4,5,6],只有4,5,6这三个数字是唯一出现的,我们只需要输出4,5,6中的一个就行。

思路:

1.这个数组元素个数一定为奇数 

假如有103个数,则有50对数,加上三个不同的数,则这三个和50对中的任何一个都不同。

2.因为3个数不相同, 三个数一定不可能每一bit位都相同。 如果每个bit位都相同,那么十进制的值也一定相等的。

我们可以找到其中一个数的bit位与其他两个不同,可以把那一个数从三个数字中分出来.

3.三个数肯定可以分到两组不同的数组里面去,基于这样的思路就可以找出这三个不同数字中的一个.

因为一位bit位只能区分两种状态,所以根据其中一个数的bit位与其他两个不同,可以把三个数中的二个分到一组,一个分到另一组。

下面用到异或的性质 

1.A^A = 0 两个相同的数异或一定等于0

2. A^0 = A 任何数和0异或都等于0本身

比如数组元素为[1,1,2,2,3,3,4,5,6]  2的二进制是  010 ,3的二进制是011 ,如果按最后一位分,

最后一位是0在第一组,最后一位是1在第二组,那么两个2 一定都在第一组,两个3 一定都在另二组,然后

2^2 与3^3 的异或结果就都等于0.  0在与其他的单个数异或,结果就等于那个数了。

将找出的数和所有数异或,相当于又放入数组一个这个数, 这时候数组中就只有两个不同的数了。

考虑“只有两个数出现一次”的情况:可以找到一种方法,将数组划分为两部分,且让这两个数分别在不同部分,

这样每部分所有数的异或值,恰好分别等于这两个数。一种简单的分法就是,先计算出这两个数的异或值M(等价于求数组中所有数的异或值),

求出M值的二进制表示中的最低位1(其它位的1也可以,只不过麻烦点)在 第k位,然后根据第k位是否为1,将原数组分为两部分。

如4,5,6的二进制分别为0100,0101,0110。因为5的的倒数第一位为1,而其他的为0,程序第一个输出的就是5了。

程序如下:

#include<stdio.h>
#include<stdlib.h>#define bit(t,i) (	(t) & (1 << (i) ))
#define N 9
int findOneDif(int arr[], int len)
{int groupA, groupB, cntA, cntB, i, j;for (i = 0; i <= 31; i++){groupA = groupB = cntA = cntB = 0;  //全部初始化为0for (j = 0; j < len; j++){if ( bit(arr[j], i))  //按倒数第i位分组,第i位为1在第一组,第i位为0在倒数第二组{groupA ^= arr[j];cntA++;}else{//groupB ^= arr[j];cntB++;}}if (cntA % 2 == 1 && groupB != 0)	{//A组是奇数个元素,另外两个不同的数在B组(B组的异或值就不等于零)。printf("%d\n", groupA);return groupA;}if (cntB % 2 == 1 && groupA != 0){//B组是奇数个元素,另外两个不同的数在A组(A组的异或值就不等于零)。printf("%d\n", groupB);return groupB;}}
}int findLastBit1(int n)
{int i;for (i = 0; i < 32; i++){if (n & (1 << i)){return i;}}
}
int main()
{int arr[] = { 1,1,2,2,3,3,4,5,6 };int bit_pos,difNum, i,a_b, groupA, groupB, dist;difNum = findOneDif(arr, N);     //找出一个出现一次的数,一会将找出的这个数和所有的数异或a_b = 0;for (i = 0; i < N; i++)			//(相当于找出的这个数在数组中出现2次)结果就等于另外两个不同的数异或,{								//因为除了三个不同的数,其他的数异或结果本来就为零。a_b ^= arr[i];}a_b ^= difNum;					//求出两个数的异或值bit_pos = findLastBit1(a_b);	//找出异或结果最后一位不为1的位置,假设为k位dist = (1 << bit_pos);				groupA = groupB = 0;for (i = 0; i < N; i++){if (arr[i] == difNum)    //将数组中找的那一个不同的数排除掉continue;if (arr[i] & dist)       //k位为1,分第一组 {groupA ^= arr[i];}else{							//k位为0,分第二组 groupB ^= arr[i];}}printf("%d %d %d\n", groupA, groupB, difNum);<span style="white-space:pre">		</span>//分出了三个数system("pause");
}


这篇关于三个数是唯一出现的,其余的都出现偶数个,找出这三个数中。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/957917

相关文章

找出php中可能有问题的代码行

前言 当你发现一个平时占用cpu比较少的进程突然间占用cpu接近100%时,你如何找到导致cpu飙升的原因?我的思路是,首先找到进程正在执行的代码行,从而确定可能有问题的代码段。然后,再仔细分析有问题的代码段,从而找出原因。 如果你的程序使用的是c、c++编写,那么你可以很容易的找到正在执行的代码行。但是,程序是php编写的,如何找到可能有问题的代码行呢?这个问题就是本文要解决的问题。 背景

hot100刷题第1-9题,三个专题哈希,双指针,滑动窗口

求满足条件的子数组,一般是前缀和、滑动窗口,经常结合哈希表; 区间操作元素,一般是前缀和、差分数组 数组有序,更大概率会用到二分搜索 目前已经掌握一些基本套路,重零刷起leetcode hot 100, 套路题按套路来,非套路题适当参考gpt解法。 一、梦开始的地方, 两数之和 class Solution:#注意要返回的是数组下标def twoSum(self, nums: Lis

集群环境下为雪花算法生成全局唯一机器ID策略

雪花算法是生成数据id非常好的一种方式,机器id是雪花算法不可分割的一部分。但是对于集群应用,让不同的机器自动产生不同的机器id传统做法就是针对每一个机器进行单独配置,但这样做不利于集群水平扩展,且操作过程非常复杂,所以每一个机器在集群环境下是一个头疼的问题。现在借助spring+redis,给出一种策略,支持随意水平扩展,肥肠好用。 大致策略分为4步: 1.对机器ip进行hash,对某一个(大于

找出有毒的那一瓶药

找出有毒的那一瓶药 找出有毒的那一瓶药问题描述求解方法二进制编码方法详细示例 找出有毒的那一瓶药 问题描述 有47瓶药,其中只有一瓶有毒。从中毒到死亡时间为4天,问最少准备几只老鼠,在4天时间内找出有毒的药? 求解方法 要在4天内确定有毒药瓶,最少需要 6 只老鼠。以下是如何使用这 6 只老鼠来找出有毒药瓶的方法。 二进制编码方法 药瓶编号: 将47瓶药瓶编号从1到

OOP三个基本特征:封装、继承、多态

OOP三个基本特征:封装、继承、多态 C++编程之—面向对象的三个基本特征 默认分类 2008-06-28 21:17:04 阅读12 评论1字号:大中小     面向对象的三个基本特征是:封装、继承、多态。     封装 封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。   封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信

前端vue项目生成唯一的uuid

一、使用步骤 1.安装uuid 代码如下(示例): npm install -S uuid 2.在需要使用uuid的.vue文件中生成并存储uuid 代码如下(示例): import { v4 as uuidv4 } from 'uuid';mounted () {let sid=''if(localStorage.getItem('sid')){sid=localStorage.g

三个同步与互斥问题之生产者与消费者

#include<stdio.h> #include<pthread.h> pthread_mutex_t  mutex; #define Max 10 pthread_cond_t pro; pthread_cond_t con; int buffer=0;//全局变量----一开始为0,只有生产者可以执行 void deal_produce(

三个同步与互斥问题之哲学家就餐

#include<stdio.h> #include <semaphore.h> #include<pthread.h> //筷子作为mutex   pthread_mutex_t chopstick[5] ;   int eatnum[5]={5,5,5,5,5}; void *eat_think(void *arg)   {       int i= *(cha

【linux 磁盘管理】Linux磁盘管理常用三个命令为df、du和fdisk。

Linux磁盘管理好坏管理直接关系到整个系统的性能问题。 Linux磁盘管理常用三个命令为df、du和fdisk。 df:列出文件系统的整体磁盘使用量du:检查磁盘空间使用量fdisk:用于磁盘分区 [root@izbp1f0leha0lvmqfhigzpz code]# dfFilesystem 1K-blocks Used Available Use% Mounted

js,找出两个数的最大公约数

/*比如说有要求a、b两个整数的最大公约数,a>b,那么我们先用a除以b,得到商8,余数r1:a÷b=q1…r1 我们当然也可以把上面这个式子改写成乘法式:a=b*q1+r1     如果r1=0,那么b就是a、b的最大公约数。 要是r1≠0,就继续除,用b除以r1,我们也可以有和上面一样的式子:b=r1*q2+r2    如果余数r2=0,那么r1就是所求的最大公约数。*/ fun