算法面试题-奇数次的数

题目:

(1)一组数中,只有一个数出现了奇数次,其余数都出现偶数次,在O(N)的时间复杂度中找出该数
(2)一组数中,有两个数出现了奇数次,其余数都出现偶数次,在O(N)的时间复杂度中找出这两个数

分析:

(1)假设eor = 0,将eor分别与该数组中的全部数进行异或,最后得到的结果就是该数。比如数组为[2,1,3,1,2], eor = 0 ^ 2 ^ 1 ^ 3 ^ 1 ^ 2 = 1 ^ 1 ^ 2 ^ 2 ^ 3 = 0 ^ 0 ^ 3 = 3
(2)假设eor = 0,将eor分别与该数组中的全部数进行异或,最后得到的结果为a^b(假设这两个数为出现奇数次的数)。此时的eor肯定有至少有一个二进位是1(因为a不等于b),假设是第8个二进制位为1, 可以将所有数分为第8位为1和为0的, a和b肯定分别属于这两个类。假设eor’= 0, 将eor’和第8位为1的数分别去异或, 出现偶数次的数依旧不会干扰结果, 最后得到的eor’=a(如果a的第8位是1)。再将eor ^ eor’ = a^b^a = b, 此时a和b都求到了

代码实现:

public static void printOddTimesNum2(int[] arr) {
        /**
         * 题2
         */
        int eor = 0, eor_dot = 0;
        for (int curNum : arr) {
            eor ^= curNum;
        }
        // eor = a ^ b  eor != 0 eor二进制位上必有一个是1
        int rightOne = eor & (~eor + 1);  // *取出eor最右边的1, 假设eor=1011, ~eor=0100, ~eor+1=0101, eor & (~eor + 1) = 0001

        for (int curNum : arr) {
            if ((curNum & rightOne) == 1) { //将eor_dot和在rightOne位置上为1的数进行异或
                eor_dot ^= curNum;
            }
        }
        System.out.println(eor_dot + " " + (eor ^ eor_dot));
    }

public static void printOddTimesNum1(int[] arr) {
	    /**
	     * 题1
	     */
	    int eor = 0;
	    for (int cur : arr) {
	        eor ^= cur;
	    }
	    System.out.println(eor);
}

tips:

要取出eor二进制最右边的1, 可以采用以下代码实现。假设eor=1011,~eor=0100, ~eor+1=0101, eor & (~eor + 1) = 0001

int rightOne = eor & (~eor + 1)
上一篇:凸多边形碰撞检测的分离轴算法(SAT)


下一篇:单层感知器练习