算法基础_3_异或

常用运算
  • 异或(xor): 如果a、b两个值不相同, 则异或结果为1. 如果a、b两个值相同, 异或结果为0
    一个数异或自己结果为零: a^a = 0
    异或运算满足交换律和结合律: (一堆数字异或结果与数字顺序无关)
    a ^ b ^ a = a ^ a ^ b = 0 ^ b = b

  • 与运算符(&)
    两个对象同时为1, 结果为1, 否则为0 (有0则0)

  • 或运算(|)
    两个对象, 一个为1, 其值为1 ( 有1则1)

public class ExclusiveOr {
	
	public static void main(String[] args) {
		learnXor();

		int[] appearArr1 = {1, 2, 3, 4, 3, 2, 1};
		appearOnce(appearArr1);

		int[] appearArr2 = {1, 2, 3, 4, 5, 3, 2, 1};
		appearTwice(appearArr2);

		System.out.println("bit1counts=" + bit1counts(1025));

	}

	private static void learnXor() {
		// 相同为0
		System.out.println("xorSelf=" + (7 ^ 7));

		// swap a,b
		int a = 7;
		int b = 8;

		a = a ^ b;
		// b = a ^ b ^ b = a ^ 0 = a
		b = a ^ b;
		// a = a ^ b ^ a = a ^ a ^ b = b
		a = a ^ b;
		System.out.println("a=" + a + " b=" + b);
	}

	// arr中,只有一种数,出现奇数次
	public static void appearOnce(int[] arr) {
		int xor = 0;
		// 偶数次的结果为0, 奇数次结果为数字本身
		// 所有数直接一起异或即可获得
		for (int i : arr) {
			xor ^= i;
		}
		System.out.println("appearOnce=" + xor);
	}

	// arr中,有两种数,出现奇数次
	public static void appearTwice(int[] arr) {
		//1. 所有数异或,获得 a ^ b (这两个奇数次数字异或的结果 xor)
		//2. a != b, 那么必然有一个位置上是1, 如果 a 在该位置上为 1, 则 b 在该位置必然为0
		//3. 获取最右侧的 1 对应的数字值, rightOne
		//4. 根据 rightOne 和数组中的每个元素进行与(&), 结果为1的则为 a 所在组; 结果为0的则为 b 所在组
		//5. 将对应组数据一起进行异或运算(^) 则可以分别得到对应 a, b; 或先求出一个分组的值, 再和xor异或得到第二个值
		//两种数为奇数次,最终必然是 a ^ b, a != b, 那么必然有一个位置上是1
		// 0110010000  ->  a
		// 0000010000  ->  b
		// 0110100000  ->  xor
		int xor = 0;
		for (int i : arr) {
			xor ^= i;
		}

		// 提取出最右的1
		// 0110100000  原值
		// 1001011111 + 1 = 1001100000  取反+1

		// 0110100000  &  进行与运算(
		// 1001100000
		// 0000100000  获取最右侧的1
		int rightOne = xor & (~xor + 1);
		int someOne = 0; // xor' 获取 a 或者 b
		for (int i = 0 ; i < arr.length;i++) {
			//  arr[1] =  111100011110000
			// rightOne=  000000000010000
			// 假设 a 在该位置为1, a 所在组与 rightOne 进行与(&)运算则不为0
			if ((arr[i] & rightOne) != 0) {
				someOne ^= arr[i];
			}
		}
		System.out.println("someOne=" + someOne + " otherOne=" + (xor ^ someOne));
	}

	//数出一个数的二进制位上有几个1
	public static int bit1counts(int N) {
		int count = 0;
		while(N != 0) {
			//找到第一个最右侧的1后,记一次
			int rightOne = N & ((~N) + 1);
			count++;
			// 去掉最右侧的1
			// N -= rightOne
			N ^= rightOne;

		}
		return count;
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值