异或在笔试题中的超神表现

直接上题目:

  • 1、在一组数中,其他每个数都出现了两次,仅有一个数,仅出现一次,找出这个数。
  • 2、在一组数中,其他每个数都出现了两次,仅有两个数,仅出现一次,找出这两个数。
  • 3、在一组数中,其他每个数都出现了三次,仅有一个数,仅出现一次,找出这个数。
  • 4、在一组数中,其他每个数都只出现一次,仅有一个数,出现了两次,找出这个数。

你能做出来几道?

解题思路:使用异或能极大程度的减小时间复杂度和空间复杂度。
完整源码:FindValue,源码记录的更全面,并且有测试案例

值的你关注并提升你薪资待遇的面试算法开源数据结构和算法实践

第一道题

  • 思路:两个相同的数进行异或为0,因此从头异或到尾,双数都被异或没了,剩下的那个就是要求的值。
  • 源码:
for (int i = 0; i < array.length; i++) {
    value ^= array[i];
}

第二道题

  • 思路:
    • 还是从头异或到尾,剩下的这个数,其实是这两个单独的数的异或,因为它不为0(为0说明两数想等,与题意不符)。
    • 所以我们总能找到某一位不为0的bit位,在这一位上,这两个数是不相同的,因此,根据这一位,把数组分成两组。
    • 再分别执行异或,就得到两个单独的数了。
  • 源码:
public int[] get(int[] array) {
    int temp = 0;
    for (int i = 0; i < array.length; i++) {
        temp ^= array[i];
    }
    int point = 1;
    for (int i = 0; i < 32; i++) {
        //从低位试探出不为0的那一位
        if ((temp & point) != 0) {
        break;
        }
        point <<= 1;
    }
    int x = 0;
    int y = 0;
    for (int i = 0; i < array.length; i++) {
        //根据这一位区分两堆数组,分别求独立数
        if ((array[i] & point) == 0) {
        x ^= array[i];
        } else {
        y ^= array[i];
        }
    }
    int[] z = new int[]{x, y};
    return z;
}

第三道题

  • 思路1
    • 先考虑这种情况:我们将每个数存起来,然后数个数,谁个数是一个,我们就输出谁。
    • 现在我们不存储数字,我们存储比特位,然后将每个bit位除以3,取余,剩下的这些个bit位,留下来的都是那单一一个数的。
  • 源码:
public int method0(int[] array) {
    //32字节
    int[] bit = new int[32];
    for (int i = 0; i < bit.length; i++) {
        for (int j : array) {
        //判断第 i 位是否位1,31-i表示正向记录,当然也可以从低位往高位记录,最后记得反转会来即可。
        int u = 1 & (j >> (31 - i));
        bit[i] += u;
        }
    }
    int sum = 0;
    for (int i = 0; i < bit.length; i++) {
        //注意此处两个表达式的顺序,先移动,把bit位置空出来承接当前值
        sum <<= 1;
        sum += bit[i] % 3;
    }
    return sum;
}
  • 思路2
    • 维持一个值,是所有出现过一次的数的异或,
    • 维持另一个值,是所有出现两次的数的异或,
    • 维持第三个值,是所有出现三次的数的异或,
    • 这些值,不停的异或数组,同时要根据取反后的其他值来刷新自己,比如说:仅记录一个数的值,需要通过和取反的记录两个数的值相与来清除自身中出现两次的数。
    • 没明白的话见参考博客,它写的比较细致。
  • 参考博客:给定一个数组,其中只有一个数出现一次,别的数都出现3次,找出这个数(go)
  • 源码:
public int method2(int[] array) {
    int one = 0, two = 0, three = 0;
    for (int x : array) {
        two ^= (x & one);
        one ^= x;
        three = one & two;
        //刷新 one 和 two
        one &= ~three;
        two &= ~three;
    }
    return one;
}

第四道题

  • 思路:
    • 这道题大概率异或是用不了的。
    • 不考虑空间复杂度的话,使用桶排序(万一数值差距很大,会导致大量空间浪费)。
    • 考虑空间复杂度的话,牺牲时间复杂度,考虑用map(红黑树之类),最后判断谁的value是2。
    • 暂时没有想到O(n)且不浪费空间的方法,有思路请留言 。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值