一个数组中有两种数出现了奇数次,其他数都出现了偶数次,寻找这两个数
1) 在一个数字序列中,有一个数出现了奇数次,其他数都出现了偶数次,找到这个奇数次的数
2) 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,寻找这两个奇数次的数
1.异或运算:
简单来讲,就是相同为0,不同为1:
1^1=0
0^0=0
1^0=1
0^1=1
此外,异或运算符合两个性质:交换律和结合律,也就是说
a ^ b = b ^ a
a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;
2.问题分析
看过问题一的小伙伴都知道了异或运算的原理,在这里就不多说了。
我们还是将这个序列的所有数都异或一下,假设这两个奇数是a和b,那么就得到了一个数a^b.
那么问题来了,如果知道a和b分别是多少呢?
根据题干我们知道,a和b肯定不相等,因此,a^b != 0,既然它不等于0,那么在二进制上肯定有一位为1,我们根据上面提到的公式提取得到最右侧为1的那个数c。
此外,a^b != 0,且最右侧有一位为1,只有0和1才能异或出来,那么我们可以断定,a和b在这一位上,肯定是一个为0,一个为1.
我们都知道,这个数c有一个特征,只有一位为1,其他位置都为0.
现在我们让c和数组arr中的所有元素进行相与,只有两个位置都为1,才能相与出来1。因此,这样我们可以把数组序列分为两类,一类是在这一位上为0的值,一类是在这一位上为1的值。
最后,我们让(a^b)得到的值分别与这两类的值进行异或,消除掉那些偶数的值,剩下的就是这两个数。
3.如何获取最右边的1
寻找一个二进制数在最右侧的1,示例:
c = 0110100
从右往左看,c在倒数第三位上的数字为1,没错,我们就是要找这个数0000100,怎么做到呢?记住下面的这个公式:
result=c&(~c+1))
&运算: &运算中1&1=1,1&0=0,0&0=0
!c = 1001011
!c + 1 = 1001100
c&(~c+1) = 0000100
记住这个算式即可
4.代码如下:
//1)在一个数字序列中,有一个数出现了奇数次,其他数都出现了偶数次,找到这个奇数 public static void printNumber(int[] arr){ int eor = 0; for (int cur : arr){
//把这个数组所有的数进行异或运算,即可得到这个奇数次的数 eor ^= cur; } System.out.println(eor); }
//2) 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,寻找这两个数 public static void printTwoNumber(int[] arr){ int eor = 0; for (int cur : arr){ eor ^= cur; }
//一个数“与” 上这个数 “取反加一” 就可以得到最右边的1 int rightOne = eor & (~eor + 1); int eor1 = 0;
//获取到两个数中的其中一个(至于是哪一个不用管它,肯定会有一个) for (int cur : arr){
//用最右边的1这个数来区分, &运算中1&1=1,1&0=0,0&0=0 if ((cur & rightOne) != 0){ eor1 ^= cur; } } System.out.println(eor1 + " " +(eor1^eor)); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)