查找-数组中重复奇数次的值

查找-数组中重复奇数次的值


前言

需要用最小的时空间复杂度来找出数组中出现奇数次的值;有2种场景:数组中只有一个奇数次的值; 有2个奇数次的值。 分别找出来


一、思路

利用整数的位运算, 运算满足各自规律, 如 ^ 满足交换律和结合律,
n^n = 0;
0^n = n;

二、题解

算法代码如下(示例):

public class OddNumSearch {
    /**
     *  要求 时 o(n) 空 o(1)
     * @param arr 给定一个数组, 只有一个数出现了奇数次
     * @return 找出这个奇数次的值
     */
    private static int oddNumSearch01(int[] arr) {
        int result = 0;
        for (int i : arr) {
            result =  result ^ i;
        }
        return result;
    }

    /**
     * 要求 时 o(n) 空 o(1)
     * 一个数组中有 2个数 奇数次出现, 找出这2个数
     * @param arr
     * @return 2个奇数次存在的数
     */
    private static int[] oddNumSearch02(int[] arr) {
        int eor = 0;
        // 得到了 eor = a ^ b 的结果
        for (int i = 0; i < arr.length; i++) {
            eor =  eor ^ arr[i];
        }
        //位运算:   ~eor 对eor的二进制位数取反
        // 找出2个数不同中 最右侧位上为1的值   eor = a ^ b a和b 二进制至少有一位是1; 找出最右侧为1 代表的那个数
        int rightone = eor &  (~eor + 1);
        int a = 0;
        for (int r : arr) {
            // 根据 rightone 将数组中的分成了2组, a 和 b 一定是在不同组
            if((r & rightone) == 0) {
                // a 代表 两个奇数之一
                a = a ^ r;
            }
        }
        // 得到 eor = a ^b 中的另一个数
        int b = eor ^ a;
        int[] oddNum = new int[2];
        oddNum[0] = a;
        oddNum[1] = b;
        return oddNum;
    }


    //打印数组中的元素
    private static void printArray(int[] arr) {
        if (arr == null) {
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int [] arr = {5, 1, 2,2,1,55,55};
        int num = oddNumSearch01(arr);
        System.out.println(num);


        int [] arr2 = {5,1,2,2,1,55,55,15};
        int[] numArr = oddNumSearch02(arr2);
        printArray(numArr);
    }
}

总结

需要熟悉java中位运算的规则,理解其底层二进制计算的逻辑

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值