题目:单个数字3
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,其中除了两个整数只出现了一次,其他所有的整数都出现了两次,找到这两个只出现一次的整数,并返回。
Note:
1、返回集中数字的顺序不重要,怎样都可以;
2、算法应该在线性时间复杂度内,能否使用常数项空间复杂度内实现?
思路一:
很巧妙的利用了Single Number 单独的数字的解法,因为那道解法是可以准确的找出只出现了一次的数字,但前提是其他数字必须出现两次才行。而这题有两个数字都只出现了一次,那么我们如果能想办法把原数组分为两个小数组,不相同的两个数字分别在两个小数组中,这样分别调用Single Number 单独的数字的解法就可以得到答案。那么如何实现呢,首先我们先把原数组全部异或起来,那么我们会得到一个数字,这个数字是两个不相同的数字异或的结果,我们取出其中任意一位为‘1’的位,为了方便起见,我们用 a &= -a 来取出最右端为‘1’的位,然后和原数组中的数字挨个相与,那么我们要求的两个不同的数字就被分到了两个小组中,分别将两个小组中的数字都异或起来,就可以得到最终结果了。
1、在计算机中,负数以其正值的补码形式表达。
2、原码:一个整数,按照绝对值大小转换成的二进制;反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码;补码:反码加1称为补码。
代码:C++版:20ms
class Solution { public: vector<int> singleNumber(vector<int>& nums) { //将nums数组中所有数字取异或操作,得到两个不相同数字异或的结果 int diff = accumulate(nums.begin(), nums.end(), 0, bit_xor<int>()); diff &= -diff; //获得最右端为1的位,因为是异或结果,所以可以通过该位将两个不相同的数分到不同小组 vector<int> res(2, 0); for (auto &a : nums) { if (a & diff) //利用得到的位将nums数组分成两个小组,采用Single Number的算法实现 res[0] ^= a; else res[1] ^= a; } return res; } };
思路二:
与思路一原理一样,只是使用lowestOneBit进行分组时,只对一个子小组进行了异或操作,而另一个数,则直接采用得到的一个结果与diff相异或得到,这样可以减少轮训nums数组时的异或操作,优化代码速度。
代码:C++版:16ms
class Solution { public: vector<int> singleNumber(vector<int>& nums) { //将nums数组中所有数字取异或操作,得到两个不相同数字异或的结果 int diff = accumulate(nums.begin(), nums.end(), 0, bit_xor<int>()); //获得最右端为1的位,因为是异或结果,所以可以通过该位将两个不相同的数分到不同小组 int lowestOneBit = diff & (~(diff - 1)); vector<int> res(2, 0); for (auto &a : nums) { if (a & lowestOneBit) //利用得到的位将nums数组分成两个小组,采用Single Number的算法实现 res[0] ^= a; } res[1] = res[0] ^ diff; return res; } };