Class002

一、异或运算

  • 特点

    N ^ 0 = N 任何数异或0等于这个数本身
    N ^ N = 0 任何数异或自身等于0
    N ^ M ^ N = N ^ N ^ M = M 异或运算满足交换律与结合律
    
  • 交换2个数问题

    a = a + b;
    b = a - b;
    a = a - b;
    
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
    

    注意:数组中同一个位置的会有问题

二、数组中找出出现奇数次的数问题

  • 只有一个数出现奇数次

    根据异或运算特点,对数组每一个元素进行异或运算,运算后的结果即是次奇数次的元素

    public int findOdd(int[] arr) {
        int eor = 0;
        for(int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }
    	return eor;
    } 
    
  • 2个数出现奇数次

    根据异或运算特点,数组中每个元素进行异或运算后的结果肯定是出现两种奇数次元素的异或结果,且此结果肯定不为0,那么就一定在二进制位上存在一个1位,找到最右侧的1位,将原数组根据元素此位是否为1进行分组异或,得出其中一个出现奇数次的数,然后根据第一次的异或结果得出第二个奇数次的数

    public int[] findOdd(int[] arr) {
        int eor = 0;
        for(int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }
        // 提取出 eor 最右侧的1
        int rightOne = eor & (- eor);
        int one = 0;
        for(int i = 0; i < arr.length; i++) {
            if((arr[i] & rightOne) != 0) {
                one ^= arr[i];
            }
        }
        int other = eor ^ one;
        return new int[]{one, other};
    }
    

三、二进制相关内容

  • 求一个数的二进制最右侧的1位

    // N   :         0000 1011 1010 1000
    //~N   :         1111 0100 0101 0111
    //~N+1 :         1111 0100 0101 1000 
    //-N == ~N + 1 : 1111 0100 0101 1000 
    int N = 10;
    int rightOne = N & (-N);
    boolean r = ((N & (-N)) == (N &((~N) +1)));
    
  • 统计一个数二进制位的个数

    public int bitCount(int N) {
        int count = 0;
        while(N != 0) {
            int rightOne = N & ((~N) + 1); // 找到最右侧的1,同 N & (-N)
            count++;
            N ^= rightOne; // 同 N -= rightOne;
        }
        return count;
    }
    
  • 一个数的二进制表示

    public String bitString(int N) {
        StringBuilder s = new StringBuilder();
        if(N == 0) {
            return "0";
        }
        int one = 1;
        // 0001 0110
        while(N != 0) {
            if((N & one) == 0) {
                s.append("0");
            } else {
                s.append("1");
            }
            N >>= 1;
        }
        return s.reverse().toString();
    }
    

四、一种数出现了K次,其他数出现了M次

public static HashMap<Integer, Integer> map = new HashMap<>();

// 请保证arr中,只有一种数出现了K次,其他数都出现了M次
public static int onlyKTimes(int[] arr, int k, int m) {
    if (map.size() == 0) {
        mapCreater(map);
    }
    int[] t = new int[32];
    // t[0] 0位置的1出现了几个
    // t[i] i位置的1出现了几个
    for (int num : arr) {
        while (num != 0) {
            int rightOne = num & (-num);
            t[map.get(rightOne)]++;
            num ^= rightOne;
        }
    }
    int ans = 0;
    for (int i = 0; i < 32; i++) {
        if (t[i] % m != 0) {
            if (t[i] % m == k) {
                ans |= (1 << i);
            } else {
                return -1;
            }
        }
    }
    if (ans == 0) {
        int count = 0;
        for (int num : arr) {
            if (num == 0) {
                count++;
            }
        }
        if (count != k) {
            return -1;
        }
    }
    return ans;
}

public static void mapCreater(HashMap<Integer, Integer> map) {
    int value = 1;
    for (int i = 0; i < 32; i++) {
        map.put(value, i);
        value <<= 1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值