求一个数组中的唯一数问题

翻看博客的时候看到了这道题,据说是阿里的一次面试题

大佬的想法也很巧妙,我在这里又总结了一下

题目一:在n个整数中,仅有1个整数出现1次,其余的整数都出现了偶数次,求这个仅出现1次的整数。要求时空复杂度尽可能低。

这道题很简单,有经验的一看就知道作异或运算

public static int getNum(int[] a){
        int n = a.length;
        int result = 0;
        for(int i = 0; i < n; i++)
        {
            result ^= a[i];
            //a^b^b=a,
            // 3 ^ 4 ^ 6 ^ 5 ^ 5 ^ 6 ^ 4
            //=3 ^ (4 ^ 4) ^ (5 ^ 5) ^ (6 ^ 6)
            //=3 ^ 0 ^ 0 ^ 0
            //=3
        }
        return result;
    }

异或运算:

a^b^b=a
=3 ^ 4 ^ 6 ^ 5 ^ 5 ^ 6 ^ 4
=3 ^ (4 ^ 4) ^ (5 ^ 5) ^ (6 ^ 6)
=3 ^ 0 ^ 0 ^ 0
=3

题目二:在n个整数中,有1个奇数仅出现一次,有1个偶数仅出现一次,其余的整数都出现了偶数次,求奇数和偶数的值。要求时空复杂度尽可能低。

结合题目一的经验,我们只需要将偶数和奇数分开处理就可以了,很简单

public static void getNums1(int[] a){
        int n = a.length;
        int result1 = 0;
        int result2 = 0;
        for(int i = 0; i < n; i++)
        {//分开奇偶处理就好了
           if(a[i]%2 == 0){//偶数
                result1 ^= a[i];
           }else {//奇数
               result2 ^=a[i];
           }
        }
        System.out.println(result1);
        System.out.println(result2);
    }

题目三:在n个整数中,有2个不同的整数分别出现1次,其余的整数都出现了偶数次,求仅出现1次的2个整数。要求时空复杂度尽可能低。

这道题就比较难了,像是第一题提升难度版,一个数组变成的两个

思路:

我们可以按照题目以的方法取出这两个唯一数的异或运算结果

然后就是想办法怎么将这个运算结果分解开变成原本的两个数字

这里举个例子:假设一个数组是{7, 1, 5, 14, 8, 8, 5, 14}

可以看到结果应该是7和1,

7的二进制表示:0111

3的二进制表示:0001

二者异或结果的二进制:0110

由于3和7不同,所以它们的二进制数中,必然存在不同的位。根据这个特征可以找出异或结果的第一个1出现在哪一位(从右往左看),而且异或完的结果必然大于小的唯一数,小于大的唯一数,

我们根据这个想法可以得到特定标志位的数字:flag=0010,(大数的这一位置必然为1)

遍历数组中这个标志位有数字的元素:

就是7^8^8^14^14=7,就求得了其中一个数字,另一个数字想必大家都会了

public static void getNums2(int[] a){
        int n = a.length;
        int result = getXOR(a);
        int flag = getFlag(result);
        int ans1=0;
        int ans2=0;
        for (int i = 0; i < n; i++)
        {
            if ((flag & a[i])>0)
            {
                ans1 ^= a[i];
            }
        }

        ans2 = ans1 ^ result;
        System.out.println(ans1);
        System.out.println(ans2);

    }

    public static int getXOR(int[] a){
        int n = a.length;
        int result = 0;
        for(int i = 0; i < n; i++)
        {
            result ^= a[i];
        }
        return result;
    }
    public static int getFlag(int xor){
        int flag = 1;
        while((flag & xor) == 0)
        {
            flag <<= 1;
        }
        return flag;
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值