剑指Offer-题56(一)(Java版):数组中只出现一次的两个数字

参考自:《剑指Offer——名企面试官精讲典型编程题》

题目:数组中只出现一次的两个数字
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

主要思路:根据异或运算的性质:数字异或它自身等于0。若数组中只有一个数字出现一次 ,其他数字都出现2次,那么从头到尾异或数组每个的数字,则最后结果就是只出现一次的数字。
  相同的思路,若能把当前题目中的数组分成两个子数组,使得每个子数组都包含一个只出现一个的数字,其他数字都成对出现,则分别对两个子数组所有数字进行异或运算,就可以得到所求两个数。拆分原数组过程:异或原数组中的所有数字,得到一个非零数字a(即为两个只出现一次的数字的异或结果,其他数字都抵消了),从右向左找出a中第一个为1的位数,所求两个数在该位数上肯定不一样(位数异或为1,说明位数的值不相同,),以该位数是否为1作为划分标准,把原数组拆分成2个子数组,则所求两个数分别在这两个子数组中。

关键点:异或运算的特点,数组拆分

时间复杂度:O(n)

public class NumbersAppearOnce
{
    public static void main(String[] args)
    {
        int[] data = {2, 4, 3, 6, 3, 2, 5, 5};
        int[] num1 = new int[1];
        int[] num2 = new int[1];
        boolean canFind = findTwoNumbersAppearOnce(data, num1, num2);
        if (canFind)
        {
            //结果:6, 4
            System.out.println(num1[0]);
            System.out.println(num2[0]);
        }
    }

    //查找数组中只出现一次的两个数字
    private static boolean findTwoNumbersAppearOnce(int[] array, int num1[], int num2[])
    {
        if (array == null || array.length < 2) return false;

        int exorResult = 0;
        for (int num : array)
        {
            exorResult ^= num;
        }
        //从右向左找到第一个为1的位的位置
        int firstOneIndex = findFirstOneBit(exorResult);

        int result1 = 0;
        int result2 = 0;
        for (int num : array)
        {
            //分成两个子数组
            if (isOneBitAt(firstOneIndex, num))
            {
                result1 ^= num;
            } else
            {
                result2 ^= num;
            }
        }
        num1[0] = result1;
        num2[0] = result2;
        return true;
    }

    /**
     * 从右向左找到第一个为1的位的位置
     *
     * @param num
     * @return
     */
    private static int findFirstOneBit(int num)
    {
        int oneBitIndex = 0;
        while ((num & 1) == 0 && oneBitIndex < 32)
        {
            num = num >>> 1;
            oneBitIndex++;
        }
        return oneBitIndex;
    }

    /**
     * bitIndex处的位数是否为1
     *
     * @param bitIndex
     * @param num
     * @return
     */
    private static boolean isOneBitAt(int bitIndex, int num)
    {
        num = num >> bitIndex;
        return (num & 1) == 1;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37862405/article/details/80501002