1. 程式人生 > >Java 實現陣列中只出現一次的數字

Java 實現陣列中只出現一次的數字

一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。

程式碼

解法一

比較笨,先排序,是的相同的數字挨在一起,這樣不同的數字必然和前後數字都不一致,對於陣列的第一個和最後一個元素,則需要單獨處理。

    public static List<Integer> findSignleAppearNumber(int[] array) {
        if (array == null || array.length <= 1) {
            return null;
        }
        // 如果陣列的長度是奇數,不可能出現兩個只出現一次的數字
        if (array.length % 2 == 1) {
            return null;
        }
        List<Integer> result = new ArrayList<>(2);
        if (array.length == 2) {
            for (int i : array) {
                result.add(i);
            }
            return result;
        }
        // 對陣列排序,使得出現兩次的數字可以挨著
        Arrays.sort(array);
        // 根據前面的判斷條件,此時陣列長度大於等於4
        // 如果第一個數字和第二個數字不相等,說明第一個數字就是隻出現一次的數字
        if (array[0] != array[1]) {
            result.add(array[0]);
        }
        // 為了和前後數字對比,第一個數字和最後一個數字不比較
        for (int i = 1; i < array.length - 1; i++) {
            // 如果一個數字和其前後兩個數字都不相等,說明該數字只出現一次
            if (array[i] != array[i - 1] && array[i] != array[i + 1]) {
                result.add(array[i]);
            }
        }
        // 如果遍歷沒有找到,說明陣列的最後一個數字是要找的
        if (result.size() < 2) {
            result.add(array[array.length - 1]);
        }
        return result;
    }


    public static void main(String[] args) {
        int[] array = {1, 2, 2, 3};
        List<Integer> list = findSignleAppearNumber(array);
        for (Integer i : list) {
            System.out.println(i);
        }
    }

解法二

藉助異或,任何一個數字異或它自己都等於0,只有都為0或者都為1,才為1,如果不相同則為0

    public static List<Integer> findSignleAppearNumber2(int[] array) {
        if (array == null || array.length <= 1) {
            return null;
        }
        // 如果陣列的長度是奇數,不可能出現兩個只出現一次的數字
        if (array.length % 2 == 1) {
            return null;
        }
        List<Integer> result = new ArrayList<>(2);
        if (array.length == 2) {
            for (int i : array) {
                result.add(i);
            }
            return result;
        }
        // 任何一個數字異或它自己都等於0,所以xor的結果是兩個只出現一次的數字的異或結果
        int xor = 0;
        for (int i = 0; i < array.length; i++) {
            xor ^= array[i];
        }
        // 找出這個異或結果二進位制第一次位為1的位置
        // 以此來將原陣列切割為兩個子陣列,每個子陣列包含一個只出現一次的數字
        // 因為位為1,說明兩個數字在該位上不相同,即必然一個在該位上是0,另一個是1,這是異或的規則所致
        // 所以以此來劃分陣列,兩個數字必然在不同子陣列之中
        int bitIndex = findFirstBitIs1(xor);
        int n1 = 0;
        int n2 = 0;
        for (int i = 0; i < array.length; i++) {
            if (is1OfBitIndex(array[i], bitIndex)) {
                n1 ^= array[i];
            } else {
                n2 ^= array[i];
            }
        }
        result.add(n1);
        result.add(n2);
        return result;
    }

    /**
     * 找出數字的二進位制上位為1的第一次出現位置
     * @param n
     * @return
     */
    private static int findFirstBitIs1(int n) {
        int bitIndex = 0;
        while ((n & 1) == 0) {
            // 如果當前位不是1,則右移一位
            n = n >> 1;
            bitIndex++;
        }
        return bitIndex;
    }

    /**
     * 判斷當前數字的第index位是否是1
     * @param n
     * @param index
     * @return
     */
    private static boolean is1OfBitIndex(int n, int index) {
        n = n >> index;
        return (n & 1) == 0;
    }