您的位置:首页 > 其它

【LeetCode】(260)Single Number III(Medium)

2015-08-24 23:35 295 查看

题目


Single Number III

Total Accepted: 3222 Total
Submissions: 9193My Submissions

Question
Solution

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?

解析

找到一个不一样的数大家都知道用异或。找到两个方法差不多,中心思想是把这两个数划分到不同的两个类里面去。如何划分呢,将所有元素做一个异或,其实本质就是对这两个元素做了异或,异或的结果其实展现的就是这两个元素的不同。

举个栗子

001, 010, 101, 101 ,111, 111, 110, 110

异或结果为011,说明那两个数最后一位是有区别的,根据这个就可以将所有的数进行划分,当然也可以根据其他的位,只要异或结果为1的位都可以。相同的元素必然划分为同一类。

这里就会划分为

001,101,101,111,111

010,110,110

然后大家都知道怎么做了,分别异或就好了。

那假如其他元素最后一位都相同,例如不是110而是1111怎么办,更简单了,会分成

001,101,101,111,111,1111,1111,

010

一样划分。

因为问题的关键在于将这两个残余的元素划分开,至于其他的元素,只有相同的划分到一起就好。

我写的代码如下

class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int sum = 0;
for (int i = 0; i<nums.size(); i++)
sum ^= nums[i];

int d = 2;
while (true)
{
if (sum%d != 0)
break;
d = d * 2;
}

vector<int> vec1;
vector<int> vec2;

for (int i = 0; i<nums.size(); i++)
{
if (nums[i]/(d/2)%2 == 0)
vec1.push_back(nums[i]);
else
vec2.push_back(nums[i]);
}
vector<int> ret(2,0);

for (int i = 0; i<vec1.size(); i++)
ret[0] ^= vec1[i];

for (int i = 0; i<vec2.size(); i++)
ret[1] ^= vec2[i];

return ret;
}
};


最后会出错,因为最后一个例子中出现了负数,负数和正数的异或有些特殊。

这里总结一下负数的存储吧,我们都知道1表示为00000001

-1想象中应该为10000001

而事实上存的时候会先将符号位以外的取反为11111110再加一为11111111

所以-3就是10000011 -> 11111100 -> 11111101

异或的结果依然有效,两个元素的差异位也不会错,但是在nums[i]/(d/2)%2 == 0 这个判断会出问题,例如-3/8 = 0 按理倒数第三位应该为0,而事实上却为1.

看看别人的代码吧

vector<int> singleNumber(vector<int>& nums) {
if (nums.size() < 2)return vector<int>();
else if (nums.size() == 2)return nums;
int all = 0;
for (auto num:nums)
all ^= num;
int flag = 0x01;
while (true) {
if (flag & all)break;
flag <<= 1;
}
int res1 = 0, res2 = 0;
for (auto num : nums) {
if (num & flag)
res1 ^= num;
else res2 ^= num;
}
vector<int> result;
result.push_back(res1);
result.push_back(res2);
return result;
}


他使用的是一个flag做掩码,判断的时候用这个数字和flag与操作,看那一位到底是什么即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: