只出现一次的数,三种题型
1.只出现一次的数I
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4
这道题很简单,将数组中所有的数字挨个抑或就行,因为两个相同的数字抑或为0,0抑或任何数就是任何数,抑或完所有的数字后,剩下的就是那个单独出现的数字
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for (const auto&e : nums)
{
res ^= e;
}
return res;
}
};
2.只出现一次的数II
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2] 输出: 3
示例 2:
输入: [0,1,0,1,0,1,99] 输出: 99
这道题,刚开始有点不好想,不妨我们直接调用库函数sort来将这个数组进行排序,之后遍历这个数组,如果当前nums[i] == nums[i+1]
直接让i += 3
跳过这个数字,直到当前两个数字不相等返回下标为i的数字就行。
class Solution {
public:
int singleNumber(vector<int>& nums) {
if (nums.empty())
return 0;
sort(nums.begin(), nums.end());
size_t i = 0;
while (i < nums.size() - 1)
{
if (nums[i] == nums[i + 1])
{
i += 3;
}
else
break;
}
return nums[i];
}
};
3. 只出现一次的数字III
给定一个整数数组
nums
,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。示例 :
输入: [1,2,1,3,2,5] 输出: [3,5]
这道题,乍一看有点懵逼。但是这道题主要体现的是一个分组的思想。
我们先将数组的数全部抑或一遍,那么剩下的数字就是那两个只出现一次的数字的抑或后的结果。
根据抑或的规则,相同为0,相反为1。那么就很容易了,我们需要先找到这个数字的二进制第一个为1的位。那么就说明,这两个数字的这一位一个为1,一个为0。然后再进行遍历数组,将数组根据条件分为两组分别再进行抑或。
怎么分呢?
如果当前数组的这一位(就是刚才找出的那个比特位)为1分为一组,为0分为一组。然后分别抑或这两组。会得到那两个只出现一次的数组。
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int ans = 0;
size_t begin = 0;
while (begin < nums.size())
{
ans ^= nums[begin];
begin++;
}
//找二进制第一个为1的位
int bit = 1;
while (1)
{
if ((bit & ans) != 0)
break;
bit <<= 1;
}
begin = 0;
int res1 = 0;
int res2 = 0;
//分组抑或
while (begin < nums.size())
{
if ((nums[begin] & bit) != 0)
{
res1 ^= nums[begin];
}
else
{
res2 ^= nums[begin];
}
begin++;
}
vector<int> rev;
rev.push_back(res1);
rev.push_back(res2);
return rev;
}
};