Leetcode 260 - Single Number III
2018-07-24 本文已影响14人
BlueSkyBlue
题目:
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] is also correct.
- Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?
思路:
这是一道关于位运算的题目。首先需要说一个关于位运算的知识点,即使用位运算进行数字之间的交换。
a = a^b
b = a^b
a = a^b
^代表着异或。异或的运算规则是两个相同的数参与运算结果为0,不同的数参与运算结果为1.
首先将给定数组中的所有数进行一次异或操作,假设在数组中各自只出现一次的数字分别是a和b。则这个最终结果为a^b。因为这个数组中除了a和b其它的数字都出现两次,一步异或操作之后全部为零。
假设a为5,b为3。
a = 0101
b = 0011
a^b = 0110
a^b中为1的位置代表着在这个位置a和b的二进制位不同。因此我们可以从右向左找到第一个a与b不同的位。设一个掩码变量mask。用于区分a和b,代表的意义就是在mask中二进制为1的位置a和b不同。
之后再重新遍历给定的数组,一旦mask&nums为0则对a进行异或操作,否则对b进行异或操作。
可能有人会问对数组中全部的数字进行异或可能会带入其它的数字导致最终的结果不同。这点不用担心,因为相同的数字二进制表示是相同的,假设nums[i]不是a或者b,但是与mask相与为1。它们在异或运算的时候由于相同会变为0。因此最后会分别得到a和b的值。
代码:
public int[] singleNumber2(int[] nums){
int [] results = new int [2];
int bitnumbers = 0;
for(int i=0;i<nums.length;i++){
bitnumbers ^= nums[i];
}
int a = bitnumbers, b = bitnumbers;
int mask = 1;
while((mask&bitnumbers) == 0){
mask <<= 1;
}
for(int i=0;i<nums.length;i++){
if((mask&nums[i]) == 0){
a ^= nums[i];
}else{
b ^= nums[i];
}
}
results[0] = a;
results[1] = b;
return results;
}