数组中有重复数字系列题

1.数组中只有一个数字出现1次,其他数字出现两次,找到只出现一次的这个数字。(题目还可以改成只有一个数字出现2(1)次,其他数字出现3次,找出那个except one)
思路:这类题实际是位运算的题,所有数字出现两次,只有个出现一次, 异或操作,都异或一遍,最后剩下的就是要求的那个数字了,那如果所有数字都出现3次呢?
可以实际不论是出现两次还是三次,我们的目的都是把这些消除掉,求最后剩下的那个,那么可以看成是二进制求模运算,数组中的数字都是32位int类型,那么一个数字如果出现两次,对应二进制上为1的位就出现2次,这时这个位应该消除为0(每个数字只出现两次),所以就是二进制模2,那么每个数字都出现3次就是二进制模3.
对于每个数字出现三次的题目,难点在于我们怎么找到一种运算等价于对数字的每个位做二进制模3呢?用两个数字ones,twos记录每一位当前的状态,用X表示下一位到来的是0还是1,可以写一个真值表啦,通过真值表能求得模3的逻辑表达式。那么最后ones代表的数就是只出现一次的那个数,而twos代表的就是只出现两次的那个数啦(是所有数出现三次而只有一个出现1次或者只有一个出现2次)。

2.这类题还有一个变种,就是说,所有数出现两次,有两个数出现1次。怎么求呢?先异或一遍得到一个数num,然后分成两队再分别异或,通过num最右边第一个出现的1的那个二进制位可以划分啦!

3.一个数组,1<=a[i]<=n,n是数组长度,有的数出现两次有的数出现1次,怎么找出出现两次的所有数?O(n) time, O(1)space.
思路:法一:找特点,数组下标是0~n-1,数组内容是1~n,有重复,

for(int i=0; i<arr.size(); i++){
        while(arr[i] != arr[arr[i]-1]){
            swap(arr[i], arr[i]);
        }
    }

这样就可以出现一次的数字比下标大1,如果不满足,一定是重复数字了。
法二:既然不能申请额外空间,那就原地当哈希表,

for(int i=0; i<arr.size(); i++){
        int index = arr[i]-1;
        if(arr[index] > 0){
            arr[index] = 0-arr[index];
        }else{
            res.push_back(index);
        }
    }

如果再次碰见负数说明这个下标位置已经找过一次了,重复。利用的是数组下标唯一并且数字范围的特点。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值