leetcode260 Single Number III
阿新 • • 發佈:2020-07-14
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:
- The order of the result is not important. So in the above example,
[5, 3]
- 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
求解思路:如果我們可以把陣列內的元素進行分類,一類裡面包含一個不同的元素和若干對相同的元素,另一類裡面有另一個不同的元素和若干對相同的元素。這樣,我們分別對兩類元素相異或,得到的結果就是兩個只出現了一次的元素。
下面對陣列內的元素進行分類:
- 首先把所有的元素相異或,相同的元素互相消去,結果為兩個不同元素的異或值,存為tmp。
- 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]
}