数据结构与算法:异或运算

异或: 相同为0,不同为1.(也可以当作"无符号相加")
在这里插入图片描述

异或满足交换律.

A ^ B ^ C ^ D =  D ^ A ^ C ^ B

不用额外变量交换两个数

public static void main(String[] args) {
        int a = 7;
        int b = 10;

        a = a ^ b;
        b = a ^ b;
        a = a ^ b;

        System.out.println(a);
        System.out.println(b);
    }

在这里插入图片描述

题目一: 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数.

public static void main(String[] args) {
        /*
        * 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
        */
        int[] arr = {1,1,2,3,3,4,4,5,5};
        int num = 0;
        for (int i = 0; i < arr.length; i++) {
            num = arr[i]^num;
        }

        System.out.println(num);
    }

题目二: 取出一个整数中最右侧的1
在这里插入图片描述

public static void main(String[] args) {
        // 2720(二进制形式:101010100000)
        int a = 2720;
        System.out.println(a & (-a));
    }

题目三:
一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数…
int[] arr = {1,1,2,2,2,3,3,4,4,4,4,5,6,6}; 2,5出现奇数次。

public static void printOddTimesNum2(int[] arr){
        int eor = 0;
        for (int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }

        // eor = a ^ b
        // eor != 0
        // eor 必然有一个位置上是1
        int rightOne = eor & (~eor + 1); // 提取出最右的1
        int onlyOne = 0;
        for (int i = 0; i < arr.length; i++) {
            if((arr[i] & rightOne) != 0){
                // 数组中的数,同rightOne相与。如果不为0,就异或。这样就能将数组中的数据分为两部分。
                onlyOne ^= arr[i];
            }
        }

        System.out.println(onlyOne +"  "+ (onlyOne^eor));
    }

题目四


import java.util.HashMap;
import java.util.HashSet;

public class CodeKM {

    public static void main(String[] args) {
        int kinds = 10;
        int range = 200;       
        int testTime = 1; // 测试次数

        int max = 9;
        System.out.println("测试开始!");
        for (int i = 0; i < testTime; i++) {
            int a = (int)(Math.random() * max)+1; // 1~9
            int b = (int)(Math.random() * max)+1; // 1~9
            int k = Math.min(a,b);
            int m = Math.max(a,b);
            if(k == m){
                // 保证k一定小于m
                m++;
            }

            int[] arr = randomArray(kinds,range,k,m);
            int ans1 = test(arr, k,m);
            int ans2 = onlyKTimes(arr,k,m);
            if(ans1 != ans2){
                System.out.println("出错了!");
            }
        }
        System.out.println("测试结束!");
    }

    public static int[] randomArray(int maxKinds, int range, int k, int m){

        int ktimeNum = randomNumber(range);
        int numKinds = (int)(Math.random()+maxKinds)+2;
        // k + (numKinds-1)*m
        int[] arr = new int[k + (numKinds-1)*m];
        int index = 0;
        for(;index<k;index++){
            arr[index] = ktimeNum;
        }

        numKinds--;
        HashSet<Integer> set = new HashSet<>();
        set.add(ktimeNum);
        while(numKinds!=0){
            int curNum = 0;
            do{
                curNum = randomNumber(range);
            }while(set.contains(curNum));
            set.add(curNum); // 将新生成的数保存在set集合中
            numKinds--;
            for (int i=0;i<m;i++){
                arr[index++] = curNum;
            }
        }

        for (int i = 0; i < arr.length; i++) {
            int j = (int)(Math.random()*arr.length);
            int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
            //System.out.print(arr[i]+" ");
        }

        return arr;
    }

    public static int randomNumber(int range){
        return ((int)(Math.random()*range)+1)-((int)(Math.random()*range)+1);
    }

    public static int test(int[] arr, int k, int m){
        HashMap<Integer,Integer> map = new HashMap();
        for(int num : arr){
            if(map.containsKey(num)){
                map.put(num,map.get(num)+1);
            }else{
                map.put(num,1);
            }
        }

        for(int num : map.keySet()){
            if(map.get(num) == k){
                return num;
            }
        }

        return -1;
    }

    // 参数arr, 只有一种数出现了k次,其他数都出现了M次
    public static int onlyKTimes(int[] arr,int k,int m){
        int[] t = new int[32];
        /*
        * t[0] 0位置的1出现了几个
        * t[i] i位置的1出现了几个
        */
        for(int num : arr){
            // 只循环32次,所以时间复杂度还是 O(n)
            for (int i = 0; i < 32; i++) {
                if(((num >> i) & 1) != 0){
                    // 表示num在第i位是1
                    t[i]++;
                }
            }
        }

        int ans = 0;
        for (int i = 0; i < 32; i++) {
            if(t[i] %m != 0){
                // i位置上除以m,有余数,则表示i位置上有1
                ans |= (1<<i);
            }
        }

        return ans;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值