数组中数字出现的次数I
题目描述:一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
解题思路一:我们可以使用hash表,对数组进行存储以及存储出现的次数,但是我们需要重新开辟另外两个整数大小的数组用来存储出现一次的数字。但是这样就不满足空间复杂度了。
解题思路二:我们可以知道,两个相同的数进行异或,那么他们最后的值是0,所以,如果在一个数组中,假设这个数组有三个值,其中两个值是一样的,那么我们对该数组的数分别异或,那么我们最后得到的值就是那个出现一次的数。但是针对该题目,我们有两个出现一次的数,那么我们就不能对该数组进行一次异或了,这样我们该怎么办呢?我们可以将两个数进行分组,保证每个组都只包含一个出现一次的数字,那么我们该怎么分组呢?我们可以对该数组中所有的数进行异或,那么最后的到的值将会是中出现一次数字的异或结果,那么,我们就可以在该二进制的数字中随便找一个是1的位置,因为在这个位置,假设出现一次的数字为a、b,那么a和b在该位置的二进制是不一样的,那么我们就可以根据这个位置对原数组进行分组,就可以保证a和b出现在不同的组中。
假设我们将所有的4换成5,结果也是一样的,只是在一个数组中只有一个数(该数是出现一次的数)
我们现在至于要对这两个数组进行异或,最后的值就是出现一次的数字
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
//求出两个只出现一次的数异或的结果
int ret=0;
for(auto n:nums)
{
ret^=n;
}
//找到上面异或结果中随便位置为1的位置,在这个位置,只出现一次的数字在这个位置是不一样的,按照这个位置将这两个数字分成两组。
int d=1;
while((d&ret)==0)
{
d<<=1;
}
//按照这个位置将原数组分为两组,保证只出现一次的数字分别在不同的组
int a=0,b=0;
for(auto n:nums)
{
if(d&n)
{
a^=n;
}
else
{
b^=n;
}
}
return vector<int>{a,b};
}
};
数组中数字出现的次数II
题目描述:在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
解题思路一:针对这个题我们也可以使用前面那道题的解法,我们也可以使用为运算,但是是对该数组中所有的数的二进制进行加法,这样得到的二进制上的每一位都是3的倍数(除了只出现一次的数的某一位二进制位置)
我们可以根据最后值的二进制,对该二进制进行记录,不是3的倍数进行记录为1,这样其他位置全为0,最后就可以得到只出现一次的数字。
int res=0;
for(int i=0,bit=0;i<32;++i,bit=0)
{
for(int num:nums)
{
bit+=((num>>i)&1);
}
res +=((bit%3)<<i);
}
return res;
解题思路二:我们可以对该数组进行排序,那么相同的数就会集中在一起,我们只需要比较调整后的数组中的数就可以,相同就直接跳三个数,然后继续比较。
sort(nums.begin(),nums.end());
int i=0;
while(i<nums.size()-1)
{
if(nums[i]==nums[i+1])
{
i+=3;
}
else
{
break;
}
}
return nums[i];
解题思路三:可以使用哈希表对该数组进行存储以及存储出现的次数,然后遍历哈希表中出现一次的数即可。
unordered_map<int,int>dict;
for(auto&i:nums)
{
++dict[i];//统计出现的次数
}
for(auto&[k,v]:dict)
{
if(v==1)
{
return k;
}
}
return 0;