問題:
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?
大意:
給出一個數字數組 nums,其中只有兩個元素只出現過一次,其余的都出現了兩次。找到只出現了一次的兩個元素。
例子:
給出 nums = [1, 2, 1, 3, 2, 5], 返回 [3, 5].
注意:
- 結果的順序不重要,所以上面的例子中 [5, 3] 也是對的。
- 你的算法應該為線性的時間復雜度。你能不能只用恒定的空間復雜度?
思路:
最簡單的方法就是排序后,依次檢查相鄰兩個數是否相等,當然遇到相等的就要跳一個數字再進行檢查,遇到不相等的就記錄下來是結果,注意如果單個的元素排序后在最末尾,要單獨處理。
這個做法排序是需要時間和空間的,并不完全符合題目的要求。
代碼(Java):
public class Solution {
public int[] singleNumber(int[] nums) {
Arrays.sort(nums);
int[] result = new int[2];
int index = 0;
int i = 0;
for (; i < nums.length-1; i++) {
if (nums[i] != nums[i+1]) {
result[index] = nums[i];
index ++;
}
else i++;
}
if (i < nums.length) result[index] = nums[i];
return result;
}
}
他山之石:
public class Solution {
public int[] singleNumber(int[] nums) {
// Pass 1 :
// Get the XOR of the two numbers we need to find
int diff = 0;
for (int num : nums) {
diff ^= num;
}
// Get its last set bit
diff &= -diff;
// Pass 2 :
int[] rets = {0, 0}; // this array stores the two numbers we will return
for (int num : nums)
{
if ((num & diff) == 0) // the bit is not set
{
rets[0] ^= num;
}
else // the bit is set
{
rets[1] ^= num;
}
}
return rets;
}
}
好的,這是一個完全符合題目要求的做法,用到了按位異或和與的操作,是什么意思呢?
首先我們要知道異或的操作是指兩個數同一位上相等時結果為0,不等時結果為1。如果是兩個相同的數字異或,結果自然為0,而0與一個數異或,結果也是那個數,按照我們數組的特性,遍歷異或后的結果將會是兩個唯一的元素的異或結果。
得到兩個數的異或結果后,我們要知道,這個結果中為0的位上說明兩個數字相同,為1的位上說明兩個數字不同,對于這一位,將數組中所有數字和其相與,必然會得到為0和為1兩個結果陣營,而我們要的兩個數就在兩個陣營之中,那怎么分別在兩個陣營中找出兩個數呢?還是上面用過的手法,遍歷異或。因為相同的兩個數一定會進入同一個陣營,異或后又變成0了,最后就會凸顯出要找的兩個數了。
上面我們說要將第一次異或后的結果中找出某一位為1的值,怎么找呢?辦法很多,這里的做法是將其與自己的負數相與,就會得出一個唯一一位為1的數了。
合集:https://github.com/Cloudox/LeetCode-Record