算法学习系列(二):位运算

72 阅读2分钟

一、按位与运算(&)

按位与"&"功能是参与运算的两数各对应的二进制位与运算。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。

//9的二进制:0000 1001
//5的二进制:0000 0101
//结果为1:  0000 0001

二、按位或运算(|)

按位或"|"功能是参与运算的两数各对应的二进制位或运算。只有对应的两个二进位均为0时,结果位才为0 ,否则为1。参与运算的数以补码方式出现。

//9的二进制:0000 1001
//5的二进制:0000 0101
//结果为13: 0000 1101

三、异或运算(^)

  • 满足交换律结合律

如果a=1,b=2,交换a,b两个数的值。 a=a^b; b=a^b; a=a^b

  • 无进制相加

a的二进制表示为 10111
b的二进制表示为 11111
a^b的结果为 01000

题目一

如果一个数组,只有一个数字出现了奇数次,其余的数都出现偶数次,找出这个数

@Test
public void test01(){
	int odd = 0;
	int[] allArray = {1,2,3,1,1,1,2,3,3};
	for (int i = 0; i < allArray.length; i++){
		odd = odd ^ allArray[i];
	}
	System.out.println(odd);
}
//控制台输出
3

题目二

如果一个数组,有两个数字出现了奇数次,其余的数都出现偶数次,找出这个数
分析:
1.出现奇数次的 a^b ≠ 0
2.a^b的结果,二进制中一定有一位是 1。即:如果a的第3位是1,那么b的第三位一定是0
3.把第3位为1的数都进行 异或运算(^),就可以得到 a这个数
4.然后再 a^b^a,就可以得到b

@Test
public void test02(){
	int odd = 0;
	//4个1,3个2,3个3
	int[] allArray = {1,2,1,2,1,2,1,3,3,3};
	//计算两个出现奇数次的异或值
	for (int i = 0; i < allArray.length; i++){
	     odd = odd ^ allArray[i];
        }
	//找到最右边的一个1所在的位置 = 2^n
	int oneLocal = odd & (~odd + 1);
	int onlyOdd = 0;
	for (int i = 0; i < allArray.length; i++){
		//一定会存在一个于 oneLocal 相同位是1的数
		// 这个数和 oneLocal进行 &运算的时候等于 0
		if((oneLocal & allArray[i]) == 0){
                //另外一种写法
                //if((oneLocal & allArray[i]) != 0){
			onlyOdd = onlyOdd ^ allArray[i];
		}
	}
	System.out.println("第一个值为:" + onlyOdd);
	System.out.println("第二个值为:" + (odd ^ onlyOdd));
}