【Leetcode每日一题】数组中数字出现的次数 C语言

【Leetcode每日一题】数组中数字出现的次数

题目

在这里插入图片描述

思路分析

看到这道题的时候,脑子里闪过两种解法:

  1. 哈希表 因为题目给的O(n)时间复杂度,所以第一秒想到的解法就是开哈希表,遍历nums记录每个数字对应的出现次数,再遍历哈希表找到出现次数为1的两个数字。但是这种解法空间复杂度远超O(1),pass
  2. 排序 既然哈希空间复杂度不够,那么就会想到用排序的做法,先把nums按从小到大进行排序,接下来只要遍历一次排序后的nums,找到没有连续出现2次的数字就行了。这下,空间复杂度确实是O(1)了,但是最快的排序时间复杂度也要O(nlogn),又变成时间复杂度不符合要求了,pass

思路到此中断。再仔细看这道题,觉得有点眼熟,想起来之前做过一道题是找出数组中只出现1次的1个数字,而这道题要求的是找出只出现1次的2个数字。前者对应leetcode 136. 只出现一次的数字,这题的标准解法是利用相同的数字异或之后的结果一定是0,对数组中所有的数字进行异或,最后得到的结果就是只出现1次的那个值,此时时间复杂度为O(n),空间复杂度O(1),刚好满足题目要求。本题中,如果将所有数字都进行异或,最后得到的结果就是只出现1次的2个值的异或,这两个数的异或可能是任何值,乍一看这个异或操作没有任何意义。但是由于一定存在2个只出现1次的值,即这两个值一定不相同,因此异或的结果一定不为0,最终结论是:这两个数一定存在某个比特位不相等。 根据这一点,可以得到最终符合题目要求的解法(以示例1为例):

  • 将nums中所有数字进行异或,得到2个只出现1次的数字的异或值:
    4 ^ 1 ^ 4 ^ 6 = 1 ^ 6 = 7 = 111
  • 取异或值7中为1的位idx(如:取最低位,idx = 0),2个目标数最低位一定不相等
  • 将nums中的数字按该位是否为1分成2组,则这两个只出现1次的数一定不在同一组,此时组1:4,4,6;组2:1
  • 现在问题转变为对这两个数组,分别完成leetcode 136. 只出现一次的数字的操作,即分别对这两个数组中的数再做异或,得到的两个数即为2个目标值
    组1:4 ^ 4 ^ 6 = 6;组2:1,即答案为[6, 1]

代码

int* singleNumbers(int* nums, int numsSize, int* returnSize){
    int *res = (int *)malloc(sizeof(int) * 2);
    *returnSize = 2;
    if (numsSize == 2) {
        return nums;
    }
    int orNum = 0;
    for (int i = 0; i < numsSize; i++) {
        orNum ^= nums[i];
    }
    int idx = 0;
    while((orNum & 1) == 0) {
        orNum = orNum >> 1;
        idx++;
    }
    int orNum0 = 0;
    int orNum1 = 0;
    for(int i = 0; i < numsSize; i++) {
        if ((nums[i] >> idx) & 1) {
            orNum0 ^= nums[i];
        } else {
            orNum1 ^= nums[i];
        }
    }
    res[0] = orNum0;
    res[1] = orNum1;
    return res;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值