题目链接: I.数组中数字出现的次数
有关题目
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。
请写程序找出这两个只出现一次的数字。
要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
2 <= nums.length <= 10000
题解
1、模拟哈希表
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
typedef struct
{
int key;
}HashTable;
void InsertNums (HashTable* Hash, int value, int flag)
{
Hash[flag].key = value;
}
int FindNums (HashTable* Hash,int target,int n)
{
int count = 0;
for (int i = 0; i < n; i++)
{
if (Hash[i].key == target)
count++;
}
return count;
}
int* singleNumber(int* nums, int numsSize, int* returnSize){
HashTable Hash[numsSize];
*returnSize = 0;
int* RetArr = (int*)malloc(2 * sizeof(int));
for (int i = 0; i < numsSize; i++)
{
InsertNums(Hash,nums[i],i);
}
for(int i = 0; i < numsSize; i++)
{
if (FindNums(Hash,nums[i],numsSize) == 1)
{
RetArr[*returnSize] = nums[i];
(*returnSize)++;
//这边不加括号跑不过去
//因为 根据*和后置++的运算级顺序
//*returnSize++等价于
//先*returnSize 再指针变量returnSize往后移一个位置
}
}
*returnSize = 2;
return RetArr;
}
2、异或
参考官方题解
让我们先来考虑一个比较简单的问题:
如果除了一个数字以外,其他数字都出现了两次,那么如何找到出现一次的数字?
答案很简单:全员进行异或操作即可。
考虑异或操作的性质:对于两个操作数的每一位,相同结果为 0,不同结果为 1。
那么在计算过程中,成对出现的数字的所有位会两两抵消为 0
最终得到的结果就是那个出现了一次的数字。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* singleNumbers(int* nums, int numsSize, int* returnSize){
int* RetArr = (int*)malloc(sizeof(int) * 2);
RetArr[0] = 0;
RetArr[1] = 0;
int i = 0;
int ret = 0;
for (i = 0; i < numsSize; i++)
{
ret ^= nums[i];
}
//001 110 按位异或
//随便找出所有数字异或完之后二级位为1的一位
int pos = 0;
for (pos = 0; pos < 32; pos++)
{
//0000 1100
if ((ret >> pos) & 1)
break;
}
//当然上面的那一步你也可以换成
//pos = 1;
//while(pos & ret)
//pos >>= 1;
for(i = 0; i < numsSize; i++)
{
if ((nums[i] >> pos) & 1)
RetArr[0] ^= nums[i];
else
RetArr[1] ^= nums[i];
}
*returnSize = 2;
return RetArr;
}
时间复杂度:O(n),我们只需要遍历数组两次。
空间复杂度:O(1),只需要常数的空间存放若干变量。