1. 程式人生 > 實用技巧 >leetcode260 Single Number III

leetcode260 Single Number III

260 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.

Example:

Input:  [1,2,1,3,2,5]
Output: [3,5]

Note:

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

分析:

思路一:HashSet

順序遍歷陣列,如果set中沒有該數字,則放入該數字,如果有該數字,則移除該數字。遍歷之後set中只剩下不重複的兩個元素

public int[] singleNumber(int[] nums) {
	Set<Integer> set = new HashSet<>();
	for (int i = 0; i < nums.length; i++) {
		if(set.contains(nums[i])) {
			set.remove(nums[i]);
		}else {
			set.add(nums[i]);
		}
	}
	int[] res = {0,0};
	Iterator<Integer> iterator = set.iterator();
	res[0] = (Integer)iterator.next();
	res[1] = (Integer)iterator.next();
	return res;
}

思路二:位操作

XOR:異或,當位不同的時候為1,相同的時候為0。如果兩個數異或之後不為0,說明兩個數不同。兩個數異或的結果上如果有一位是1,則這個1一定來自於這兩個數中的一個。

有一串二進位制數為X,X&(-X) 的結果是 X 最右邊的 1 的位置。詳細見https://www.cnblogs.com/yzxag/p/12668034.html

求解思路:如果我們可以把陣列內的元素進行分類,一類裡面包含一個不同的元素和若干對相同的元素,另一類裡面有另一個不同的元素和若干對相同的元素。這樣,我們分別對兩類元素相異或,得到的結果就是兩個只出現了一次的元素。

下面對陣列內的元素進行分類:

  1. 首先把所有的元素相異或,相同的元素互相消去,結果為兩個不同元素的異或值,存為tmp。
  2. tmp 的二進位制一定有一個或一個以上的 1,且這個 1 一定來自於兩個數字中的一個。用tmp & (-tmp)選出一個 1,再次遍歷陣列,如果該位置上為 1 分入類別一,否則分為類別二。對兩個類別中的元素進行異或,得到兩個單獨的數字。
public int[] singleNumber(int[] nums) {
	int tmp = 0;
	for (int num : nums)	// 得到所有數字異或的結果
		tmp ^= num;
	int dif = tmp & (-tmp);	// 選取出最右邊的一個 1
	int[] res = new int[2];
	for (int num : nums)	// 再次遍歷,如果該位置上為 1,則進行異或,得到其中一個數字
		if ((num & dif) != 0)
			res[0] ^= num;
	res[1] = tmp ^ res[0];	// tmp 為兩個不同元素的異或結果,即 tmp = res[0]^res[1],
	return res;				// res[1] = res[0]^res[1]^res[0]
}