剑指 Offer 56 - I. 数组中数字出现的次数

I.数组中数字出现的次数


题目链接: 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),只需要常数的空间存放若干变量。

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值