找到数组中出现奇数次的一/二个数

异或法找数

一. 给出一个数组,数组中仅有一个数出现奇数次,找出这个数

示例: 找到数组 [ 1, 2, 2, 1, 1 ] 中出现奇数次的数(1)

解决思路:

  1. 首先了解位运算的异或运算,例如:101 ^ 111 = 010(相同位上数字相同异或是0,相同位数字不同是1)
  2. 异或运算是满足交换律的,例如:a ^ b ^ c 与 b ^ c ^ a 的结果相同,(a ^ b)^ c 和 a ^ (b ^ c)相同
  3. 对于示例数组开始从左到右开始异或运算,1 ^ 2 ^ 2 ^ 1 ^ 1 = 1(偶数次出现的数字都被异或为0了,而0与任何数字 X 异或后都是 X)
  4. 此时就找到了要找的数字

代码示例:

public class Test {
  public static void main(String[] args) {
      int arr[] = { 1, 1, 2, 2, 2, 3, 3 };
      int res = 0; // 0和任意的X异或都是X
      for (int i: arr) {
          res ^= i;
      }
      System.out.println(res);
  }
}

得到的结果是:2

二. 给出一个数组,数组中有两个数出现奇数次(两个数不相同),找出这两个数

示例: 找到数组 [ 1,2,2,1,1,3,3,3 ] 中出现奇数次的两个数(2 和 3)

解决思路:

  1. 假设有一个数组[ a, b, a, a, b, b, c, c ] 此数组内部从第一个开始做异或运算到最后一个,会得出结果 result= a ^ b
  2. 由于a 和 b 是不同的,所以步骤1得到的result必定不为0。找到不同的某个位(假设此时的a为7(二进制为 111),b为6(二进制为 110),那么显然他们第3位是不同的)
  3. 此时根据不同的位进行把原数组进行划分,例如步骤2中知道了第3位是不同的,此时把原数组中所有第3位为1的归纳为一类(命名为A类),第3位不为1的归纳为另外一类(命名为B类),显然a(111)此时是属于A类的,b(110)属于B类
  4. 假设选出A类的所有数进行逐个异或操作,就能找到A类中出现次数为奇数次的数(a),把他记为 resA
  5. 把步骤4中得到的resA(resA此时存的为a)与result进行异或,过程为 a ^ a ^ b = b,此时 a 与 b 均找出
public class Test {
    public static void find(int a[])
    {
        int ero = 0;
        for (int i : a)
        {
            ero ^= i;
        }
        int rightOne = ero & (~ero + 1);

        int resA = 0;  // 用来存其中一个值
        for (int cur: a){
            if ((cur & rightOne) == 0) {
                resA ^= cur;
            }
        }
        System.out.println(resA + "和" + (ero ^ resA));
    }

    public static void main(String[] args) {
        int arr[] = { 6, 6, 7, 7, 7, 5, 5, 5 };
        find(arr);
    }
}

结果为: 7 和 5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值