寻找缺失的整数

        位运算:如果一个问题能用到位运算,那么它的的运算性能可大大提升。

        场景一:在一个无序数组里有99个不重复的正整数,范围是1~100,唯独缺少1个1~100中的整数。如何找出这个缺失的整数?

        问题分析:方法一,可双重遍历得到缺失值,时间复杂度为O(n^2)。方法二,可预先将全部的正整数放入到创建的map中,遍历数组时再删除map中对应的值,最后留下来的值即为确实的值。方法三,先将100内的正整数累加,再减去数组中的全部正整数。

public class FindLostNum {
    public static void main(String[] args) {
        FindLostNum findLostNum = new FindLostNum();
        int[] num = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        System.out.println(findLostNum.findLostNumV1(num));
        num = new int[]{1, 2, 1, 2, 5, 6, 5, 5, 5};
        System.out.println(findLostNum.findLostNumV2(num));
        num = new int[]{1, 2, 1, 2, 5, 6, 5, 5, 5, 7};
        Arrays.stream(findLostNum.findLostNumV3(num)).forEach(System.out::print);
    }

    private int findLostNumV1(int[] num) {
        int sum = (1 + 10) * 10 / 2;
        for (int i = 0; i < num.length; i++) {
            sum -= num[i];
        }

        return sum;
    }
}

         场景二:一个无序数组里有若干个正整数,范围是1~100,其中99个整数都出现了偶数次,只有1个整数出现了奇数次,如何找到这个出现奇数次的整数?

        问题分析:利用异或的性质,相同为0,相异为1。那么数组中相同的数异或则必为0,最后得到的结果即为出现奇数次的整数。

    private int findLostNumV2(int[] num) {
        int lost = 0;
        for (int i = 0; i < num.length; i++) {
            lost = lost ^ num[i];
        }
        return lost;
    }

         场景三:假设一个无序数组里有若干个正整数,范围是1~100,其中有98个整数出现了偶数次,只有2个整数出现了奇数次,如何找到这2个出现奇数次的整数?

        问题分析:此问题难点在于有两个整数出现奇数次,如果我们能够找出这两个整数的区别,再套用场景二便可解决。这里用到了分治算法,设这两个整数为A,B。1.先将数组内元素异或得到A,B的异或值。2.将该值对应的二进制位从右至左找到第一个为1的值sep,表示A,B对应的二进制表示在此处的位置相异,设A为1,B为0。3.利用此区别,将数组中的其他元素和sep相与,为1和A划为一组,为0和B划为一组。4.利用场景二求解。

    private int[] findLostNumV3(int[] num) {
        int[] result = new int[2];
        //查找两奇数次整数的异或值
        int lost = 0;
        for (int i = 0; i < num.length; i++) {
            lost = lost ^ num[i];
        }

        //从右到左确定,确定分割点
        int separator = 1;
        while ((separator & lost) == 0) {
            //separator左移一个单位
            separator >>= 1;
        }

        //分治算法
        for (int i = 0; i < num.length; i++) {
            if ((separator & num[i]) == 0) {
                result[0] ^= num[i];
            } else {
                result[1] ^= num[i];
            }
        }

        return result;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值