《算法自学记录》——数组中找出数量为单数的数

题目描述:

一个数组中,有若干种数,出现次数为单数和双数,假如只有一种出现为单数的数,怎么找出来?

例:[8,2,3,8,2,2,2]

预期结果:[3]


思路:

第一种:介于本身实力有限,首先想到最简单的实现就是存HashMap,遍历数组存放不同键中,每次相同value+1,但频繁遍历+get可想而知效率就不谈了。
第二种:用异或(^)这种位运算来解决(因为位运算是底层二进制运算,所以速度非常快)

什么是异或运算

异或就是一种无进位相加的思想,相同位相加得0(1和1不会产生进位),异位相加得1

 

所以上述可推出两个异或非常关键的公式:

1.0^a = a

2.a^a = 0 

由此可得偶数个数异或的结果都为0,因此把数组中每一个数都进行异或运算,得出最后为单数的那个数。


实现java代码:

public class FindOddNumberInArray {
    public static int findOddNumberInArray(int[] arr) {
        int result = 0;
        for (int cur: arr) {
            result = result ^ cur;
        }
        return result;
    }

    public static void main(String[] args) {
        System.out.println(findOddNumberInArray(new int[]{8,2,3,8,2,2,2}));
    }
}

拓展:

拓展:假如出现为单数的数为两种,怎么找出来

例:[8,2,3,8,2,2,2,4]

预期结果:[3,4]

通过上述的了解,暂时认为要求的数是a和b,进行异或运算时得到的最终结果是a^b,这里知道a和b是两种不同的数,所以得出a^b != 0,所以能推出a^b必然有一位是1,那么从数组整体角度上来看现在只有两种数,一种是某一位为1的数,一种是某一位为0的数,正因为他们分别都是偶数,所以可以先求出某一位为1的那一个单数或者某一位不为1的那个单数(这里我理解是向下拆分成两组,得出某一个单数),得到的单数和a^b做异或运算就可以得出另外的数。

看下代码实现:

public static int[] findTwoOddNumberInArray(int[] arr) {
        int xor = 0;
        int result = 0;
        for (int cur: arr) {
            xor = xor ^ cur;
        }

        int right = xor & (~xor + 1); //提取出最右侧的1
        for (int cur: arr) {
            if ((cur & right) == 0) {
                result = result ^ cur;
            }
        }
        return new int[]{result,result^xor};
    }

这里解释一下这行:int right = xor & (~xor + 1)

a的非运算就是按位取反,与(&)运算就是只有都为1的时候才为1,所以如图就求出最右侧1代表的数(这里应用的就是原码与补码加1取出最右侧的1,想了解这部分知识的可以去看下原码和补码的知识 )

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值