在Single Number的基础上,只出现一次的数字从一个变成了两个,同样地我们仍然希望使用xor的技巧来方便地得到两个只出现一次的数字,所以我们需要思考一种方法将给出的数字分为两堆,每堆含有的除了一个只出现一次的数字之外,其他都是出现两次的数字。这样我们就可以在这两堆上分别进行xor得到两个值。
这里我们采用的方法是首先对所有的数字进行xor,得到的值也就是两个只出现一次的数字的xor值,接下来我们寻找得到的结果的二进制从右向左看第一个为1的那一位,根据xor的性质,我们可以知道:两个只出现一次的数字在这一位上是不同的,一个为0,一个为1。所以我们可以根据这一位的不同将数字分为两堆,然后分别进行累计的xor操作。这里有一个小技巧,不需要另外new出两个ArrayList来存储这两堆数字,只要用两个初始值为0的int值,然后分别对它们进行累计xor即可,时间复杂度为O(n),代码如下:
public class Solution {
public int[] singleNumber(int[] nums) {
if(nums == null || nums.length == 0){
return new int[0];
}
int[] result = new int[2];
int xor = 0;
for(int i = 0; i < nums.length; i++){
xor ^= nums[i];
}
// Find the last digit == 0, and divides nums according to it
int lastBit = xor - (xor & (xor - 1));
int group0 = 0;
int group1 = 0;
for(int i = 0; i < nums.length; i++){
if((lastBit & nums[i]) != 0){
group1 ^= nums[i];
}else{
group0 ^= nums[i];
}
}
// Construct result
result[0] = group0;
result[1] = group1;
return result;
}
}
知识点:
1. 变量一定要先初始化后再使用,而如果要累计计算^=值的时候,可以把变量初始化为0,因为a ^ 0 = a
2. Java中不可以将非0的int值放到if语句中进行条件判断,需要另外进行逻辑判断得到一个boolean的值,才可以将其用作条件判断
3. number - (number & (number - 1))或者number & (~(number - 1))可以用来得到某个数二进制形式下从右向左看第一个为1的那一位