数组里很多数出现了两次,三个数出现一次,找出这三个数

该博客介绍了如何利用异或运算解决找出数组中仅出现一次的三个数的问题。通过将所有数进行异或操作,得到一个与三个数相关的值。然后通过分析异或结果的奇偶性,找到这三个数中的一个,并逐步分离出其余两个。最后,通过代码实现详细展示了这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数组里很多数出现了两次,三个数出现一次,找出这三个数

思路

异或运算解决奇偶性问题。

所以把所有数进行异或即可得到一个只跟这三个数有关的值,记为flag

更精确的:

  1. 如果flag某一位是0,表示这三个数中这一位,1的个数为偶数
  2. 如果是1,表示对应位上,1的个数位奇数

那么,如果用flag与这三个数相异或,所得的三个结果记为r1,r2,r3,那么每一位上都只有偶数个1(r1^r2^r3==flag^a^flag^b^flag^c==0)。

我们就可以通过这个性质解决问题了,可以通过r1,r2,r3最低bit的位置来找出这三个数中的一个,记为b,因为一定有一个最低bit位与其余两个不同。

找到b了之后,我们让flag = flag^b,也就是a^c的值,这个时候我们随便找一位为1的位置去判断就可以分辨出a和c了

lowerbit函数表示取最低一个比特,最优雅的方式如下

	  public int lowBit(int x) {
        return x & (-x);
    }

最终代码如下

    public void solution(List<Integer> nums) {
        int len = nums.size();
        int flag = 0;
        //对所有的数进行异或,最终结果就是a^b^c
        for (int i = 0; i < len; i++) {
            flag ^= nums.get(i);
        }
        int symbol = 0;
        //获得a,b,c中的第一个区分点,即flag^a flag^b flag^c中最低位不同的那一位,用于接下来找出不同的这一个数
        for (int i = 0; i < len; i++) {
            symbol ^= lowBit(flag ^ nums.get(i));
        }
        int b = 0;
        //通过判断flag^x的最低位是否等于symbol来区分出3个数中的一个,记为b
        for (int i = 0; i < len; i++) {
            if (lowBit(nums.get(i) ^ flag) == symbol) {
                b ^= nums.get(i);
            }
        }
        //获得a^c并把b添加到序列里去
        flag ^= b;
        nums.add(b);
        int a = 0, c = 0;
        //把集合中的数分成两半,一半是跟a^c有同样最低位的数,一半是没有的。这两半中一半有a,一半有c
        for (int i = 0; i < nums.size(); i++) {
            if ((nums.get(i) & lowBit(flag)) == 0) {
                a ^= nums.get(i);
            } else {
                c ^= nums.get(i);
            }
        }
        System.out.println(MessageFormat.format("{0} {1} {2}", a, b, c));
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值