位运算:异或(附算法)

文章目录

  • 一、两道算法题
  • 二、异或运算 介绍
  • 三、算法解题思路
    • 1、求1个单数出现的数值。
    • 2、求2个单数出现的数值。
  • 四、算法解题代码

一、两道算法题

  • 有一批数值,其中只有1个数值是单数出现的,其他数值都是双数出现的,求这个单数的数值。
  • 有一批数值,其中有2个数值是单数出现的,其他数值都是双数出现的,求这2个单数的数值。

(如:1、2、3、2、1、4、4,这里面只有3只出现了1次,是单数出现的)

要求:时间复杂度 O(N)   空间复杂度O(1)

二、异或运算 介绍

  如果a、b两个值不相同,则异或结果为1。. 如果a、b两个值相同,异或结果为0。异或也叫半加运算,其运算法则相当于不带进位的二进制加法。

  计算示例如下:

a = 4, b = 9
a^b的表达式为

0100
1001
-----
1101

  运算规则:

1、0 ^ N = N ; N ^ N = 0
2、a ^ b = b ^ a
3、(a ^ b) ^ c = a ^ (b ^ c)

  实际应用(借用上面的运算规则理解):

/**
 * 交换数值(用于理解异或运算,但是不建议这样交换数值)
 *
 * @param a 参数
 * @param b 参数
 */
private static void swap(int a, int b) {
    a = a ^ b;  //a = a ^ b;  b = b
    b = a ^ b;  //a = a ^ b;  b = (a ^ b) ^ b = a
    a = a ^ b;  //a = (a ^ b) ^ a = b;  b = a
    System.out.println(a + " " + b);
}

三、算法解题思路

1、求1个单数出现的数值。

  定义一个全局变量:int eor = 0;
  遍历整个数组中的值,分别和eor进行异或。最终eor的值就是这个单数的数值。

(相同的数值异或为零,所以出现了偶数次的数值都被抵消掉了,最终剩下的即是答案。)

2、求2个单数出现的数值。

(假设这两个值分别为a b)

  重复刚刚解题1的步骤,将双数的值抵消掉,最终eor的值为a^b;
  因为是答案是2个单数,所以这两个值肯定不相等。即a^b != 0;
  所以a^b在某一位上肯定为1,(a = 1,b = 0 或 a = 0, b = 1)

  因为eor=a^b,所以看eor哪一位为1,取出来这一位。(假设eor = 6,那么eor二进制位:0110,取最右边第一个1,即为2)

  由此,通过上一步取出来的这一位,假设为2,那么将所有的数值与2进行与运算(与运算结果为0或者2),可以得到两个子集合(a和b肯定分别在这两个集合中,相同的数值肯定在同一个集合)。

  这两个集合的元素分别进行异或运算,最终两个集合都会只剩下一个值,即是我们求的两个值。

四、算法解题代码

未完待续

你可能感兴趣的:(java,算法)