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.
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?
上两个的升级版,但是跟上两个思路又完全不同。真是。。。
两种做法,一个位运算肯定是技巧性很高的,一个是set维护。
Java set做法:
遍历这个数组,第一次出现的添加进去,只要出现了第二次,则remove,剩下的就是单个了的数集合了,也适用用于找出数组中成对出现数中的所有单个数。最后把这个set集合元素添到数组就行了。
查了资料,貌似不能直接把一个set集合转换成Array,toArray也只能装换成object,参考可见:https://ask.helplib.com/106360。
public class Solution { public int[] singleNumber(int[] nums) { Set<Integer> set = new HashSet<Integer>(); for(int n : nums) { if(!set.contains(n)) { set.add(n); }else { set.remove(n); } } int[] ans = new int[set.size()]; int cnt = 0; for(int n:set) { ans[cnt++] = n; } return ans; } }
位运算做法:
这个需要很强的计算机底层二进制思想,看到这个题目后,看到这个数字大脑里就想到的是这个数字背后的二进制。
1.不管以哪个数开始 ^ 两个相同的数,都会抵消。
2.diff &= -diff; 或者 diff = diff & (~(diff - 1));求出从右开始第一位不相同的位数,用来区分出数组中两个不同的数。保留该位并将其他位置为 0 再进行与运算,结果一个肯定为0,另一个与运算肯定不为0,再进行下面的(3。
3.ans[] = {0},0和任意一个数^亦或得它本身,区分后靠这个直接赋值给ans。
一开始傻逼了,就因为这个3有点唬住了,其实也可以直接取。当然也可保留其他diff的数值为1的位,因为1位都是两个数当前位不同亦或的结果,但是为了简单只保存一个即可。
public class Solution { public static int[] singleNumber(int[] nums) { int[] ans = new int[2]; int diff = 0; for(int num : nums) { diff ^= num; } diff &= -diff; for(int num : nums) { if((num & diff) == 0) { ans[0] ^= num; }else { ans[1] ^= num; } } return ans; } }