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]
}
上一篇:SinGAN: Learning a Generative Model from a Single Natural Image - 1 - 论文学习


下一篇:0260. Single Number III (M)