Leetcode - Single Number III

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

For example:

Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].

Note:
The order of the result is not important. So in the above example, [5, 3] is also correct.
Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

[分析]
参考 https://leetcode.com/discuss/52351/accepted-java-space-easy-solution-with-detail-explanations,粘贴下作者解析:
引用
Once again, we need to use XOR to solve this problem. But this time, we need to do it in two passes:
In the first pass, we XOR all elements in the array, and get the XOR of the two numbers we need to find. Note that since the two numbers are distinct, so there must be a set bit in the XOR result. Find out the bit.
In the second pass, we divide all numbers into two groups, one with the aforementioned bit set, another with the aforementinoed bit unset. Two different numbers we need to find must fall into thte two distrinct groups. XOR numbers in each group, we can find a number in either group.

Complexity:
Time: O (n)
Space: O (1)


http://www.cnblogs.com/daijinqiao/p/3352893.html 这篇博客中作者给出更一般化的扩展:
引用
给定一个包含n个整数的数组,有一个整数x出现b次,一个整数y出现c次,其他所有的数均出现a次,其中b和c均不是a的倍数,找出x和y。
思路:使用二进制模拟a进制,累计二进制位1出现的次数,当次数达到a时,对其清零,这样可以得到b mod a次x,c mod a次y的累加。遍历剩余结果(用ones、twos、fours...变量表示)中每一位二进制位1出现的次数,如果次数为b mod a 或者 c mod a,可以说明x和y的当前二进制位不同(一个为0,另一个为1),据此二进制位将原数组分成两组,一组该二进制位为1,另一组该二进制位为0。这样问题变成“除了一个整数出现a1次(a1 = b 或 a1 = c)外所有的整数均出现a次”,使用和上面相同的方式计算就可以得到最终结果,假设模拟a进制计算过程中使用的变量为ones、twos、fours...那么最终结果可以用ones | twos | fours ...表示。

我实现了一个具体的例子,一个数组中有一个数出现了1次,一个数出现了两次,其余数均出现了3次。代码有些长,希望面试中不用写这么繁琐的扩展~O(∩_∩)O

public class Solution {
    public int[] singleNumber(int[] nums) {
        int xor = 0;
        for (int num : nums) //记仅出现一次的两数为a和b, for 循环结束,xor=a^b
            xor ^= num;
        xor &= -xor; // set a 和 b 第一个不同的数位为1,其余位为0
        
        int[] ret = {0, 0};
        for (int num : nums) {
            if ((num & xor) == 0)
                ret[0] ^= num;
            else
                ret[1] ^= num;
        }
        return ret;
    }
}


import java.util.ArrayList;

public class OutlierNumbers {

    public static void main(String[] args) {
        OutlierNumbers obj = new OutlierNumbers();
        int[] nums = {1,2,2,3,3,3,4,4,4,5,5,5};
        int[] ret = obj.getOutliers(nums);
    }
    
    // 一个数出现a次,一个数出现b次,其余数均出现c次的一个具体化例子: a = 1, b = 2, c = 3
    public int[] getOutliers(int[] nums) {
        int ones = 0, twos = 0;
        int mask = 0;
        for (int num : nums) {
            twos |= (ones & num);
            ones ^= num;
            mask = ~(ones & twos);
            ones &= mask;
            twos &= mask;
        }
        int xor = ones ^ twos;
        xor &= -xor;
        int[] ret = new int[2];
        ArrayList<Integer> group1 = new ArrayList<Integer>();
        ArrayList<Integer> group2 = new ArrayList<Integer>();
        for (int num : nums) {
            if ((xor & num) == 0)
                group1.add(num);
            else
                group2.add(num);
        }
        int[] array1 = arrayList2Array(group1);
        int[] array2 = arrayList2Array(group2);
        if (array1.length % 3 == 1)
            ret[0] = getOneOutlier(array1, true);
        else
            ret[0] = getOneOutlier(array1, false);
        if (array2.length % 3 == 1)
            ret[1] = getOneOutlier(array2, true);
        else
            ret[1] = getOneOutlier(array2, false);
        System.out.println(ret[0] + " " + ret[1]);
        return ret;
    }
    public int getOneOutlier(int[] nums, boolean outlierOccurOne) {
        if (nums == null) return Integer.MAX_VALUE;
        if (nums.length < 3) return nums[0]; 
        int ones = 0, twos = 0;
        int mask = 0;
        for (int num : nums) {
            twos |= (ones & num);
            ones ^= num;
            mask = ~(ones & twos);
            ones &= mask;
            twos &= mask;
        }
        if (outlierOccurOne)
            return ones;
        else
            return twos;
    }
    
    public int[] arrayList2Array(ArrayList<Integer> list) {
        int[] array = new int[list.size()];
        for (int i = 0; i < list.size(); i++)
            array[i] = list.get(i);
        return array;
    }
}

猜你喜欢

转载自likesky3.iteye.com/blog/2236116