栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java算法体系学习(一)异或运算及其在题目中应用技巧

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java算法体系学习(一)异或运算及其在题目中应用技巧

文章目录
  • 一、异或及相关题目
    • 1、不使用额外变量交换数组中两个位置元素数
    • 2、一个数组中一个数出现了奇数次,剩下数都出现了偶数次,找到并打印
    • 3、给定一个整型的数,提取出二进制下最右边的1
    • 4、一个数组中两种数字出现了奇数次,其余都出现了偶数次,找到并打印这个数
    • 5、一个数组中有一个数出现k次,其他数出现了M次(K < M 且 M > 1,O(N)时间复杂度)

一、异或及相关题目
  • 异或:一种二进制运算,对应位相同为0,不同为1
  • 0 ^ N = 0
  • N ^ N = 0
  • 1 ^ N = !N
  • (a ^ b) ^ c = a ^ (b ^ c)
  • a ^ b = b ^ c
  • 可以简单理解,遇0不变,遇1翻转
1、不使用额外变量交换数组中两个位置元素数
  • 要求两个位置不能相同
  • 做法:三次异或,设待交换元素分别为a,b
    1. a = a ^ b
    2. b = a ^ b (由第一的a b = a ^ b = a ^ b ^ b = a)
    3. a = a ^ b (由第一步的a和第二步的b a = a ^ b = a ^ b ^ a = b)
  • 不能为同一位置是因为 arr[index] = arr[index] ^ arr[index] = 0,这样最终结果都会为0
package xor;

public class Swap {
    
    public static void swap(int[] arr,int index1,int index2){
        if(index1 == index2){
            return;
        }

        arr[index1] = arr[index1] ^ arr[index2];
        arr[index2] = arr[index1] ^ arr[index2];
        arr[index1] = arr[index1] ^ arr[index2];
    }
}

2、一个数组中一个数出现了奇数次,剩下数都出现了偶数次,找到并打印
  • 由异或特性可知道,一个数异或上自身为0。既然数组中只有一个数出现了一次,剩下都出现偶数次。那么可以把数组元素依次异或,出现偶数次的元素异或后都为0,最后只剩0与奇数次的元素异或,那么得出的就是奇数次元素。

  • 举例:arr = [2,4,5,2,4]

    result = 2 ^ 4 ^ 5 ^ 2 ^ 4 = (2 ^ 2) ^ (4 ^ 4) ^ 5 = 0 ^ 0 ^ 5 = 5 (异或满足交换律和结合律,任意数与0异或不变)

package xor;

public class FindOdd {
    
    public static int findOdd(int[] arr){
        int result = arr[0];
        for(int index = 1;index < arr.length ;index++ ){
            result ^= arr[index];
        }

        return result;
    }
}

3、给定一个整型的数,提取出二进制下最右边的1
  • 举例 num = 6 = (110)2 ,最右边的1在倒数第二位,返回(010)2 = 2

  • 思路:对该数进行取反加1,在与原数进行与运算

    6 =- 110

    ~6 = 001

    ~6 + 1 = 010

    010 ^ 110 = 010

  • 取反后,原数二进制尾部为0的位会全部变为1,加上1之后会一直进位到原数最右边1的位置,因为原数进行了取反,所有取反后原数最后右边1的位置为0,再加上1后就是1,此时只有该位为 1 & 1,其他位由于取反的缘故再进行与运算全为0。

package xor;

public class FimdRightOne {
    
    public static int findRightOne(int num){
        return num & (~num + 1);
    }
}

4、一个数组中两种数字出现了奇数次,其余都出现了偶数次,找到并打印这个数
  • 三次异或
  1. 首先全体异或一次,得出的结果为两个出现奇数次的元素异或
  2. 找出第一次结果最右边的1,(本质是找到两个出现奇数次元素从低位开始第一个不同的位置)这个数将所有元素分为两类,该位为1和为0
  3. 如果该位为1则进行异或,这样可以解出一个数,因为偶数次会消掉,两个不同的奇数该位必定不同,所有会得到其中一个
  4. 将这个数与全体异或一次接出另一个数
package xor;

public class EvenTimes {
    
    public static int[] evenTimes(int[] arr) {
        int eor = 0;
        //全体异或一次
        for (int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }

        //解出两个数中最右边首先为1的那个数的对应位置
        int rightOne = eor & (~eor + 1);

        //根据该位将数组元素化为两类,该位1 和 该位0
        int onlyOne = 0;
        for (int i = 0; i < arr.length; i++) {
            if ((rightOne & arr[i]) != 0) {
                onlyOne ^= arr[i];
            }
        }

        eor ^= onlyOne;
        return new int[]{eor,onlyOne};
    }
    
}

5、一个数组中有一个数出现k次,其他数出现了M次(K < M 且 M > 1,O(N)时间复杂度)
  • 生成一个32位数count数组,把所有数字变为32bit表示,若为1则数组的对应位置加1。把数组所有数都进行同样操作过后。依次遍历32位的数组。
  • count数组的没个位置元素只能出现两种情况(n * m)和 (n * m + k),n为数组中该位为1的不同数个数。若该位置的数字能整除m,则说明该位置的数是出现m次的,也就是该位置肯定为 n * m。若该位除不尽,则必为(n * m) + k,也就是出现k次的那个数字该位为1。
  • 最后找到所有除不尽m的位置,从二进制恢复该元素
  • 可能出现一种特殊情况,如果0出现了k次,则需要检查,因为所有位置都能除尽m
package xor;

public class FindKTimesNumber {
    
    public static int findKTimesNumber(int[] arr, int k, int m) {
        //将所有数字拆分为32bits的数字
        int[] count = new int[32];
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j <= 31; j++) {
                count[j] += (arr[i] >> j) & 1;
            }
        }

        //恢复出现k次的数字
        int res = 0;
        for (int i = 0; i < 32; i++) {
            if (count[i] % m != k) {
                res |= (1 << i);
            }
        }

        //可能出现一种特殊情况,如果0出现了k次,则需要检查,因为所有位置都能除尽m
        if (res == 0) {
            //记录0出现的次数
            int countZero = 0;
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] == 0) {
                    countZero++;
                }
            }
            if (countZero != k) {
                return -1;
            }
        }
        return res;
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/684683.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号