位运算 01

149 阅读1分钟

LeetCode面试题56 - I. 数组中数字出现的次数

面试题56
原题链接

异或的性质

  • 交换律:p ⊕ q = q ⊕ p

  • 结合律:p ⊕ (q ⊕ r) = (p ⊕ q) ⊕ r

  • 恒等率:p ⊕ 0 = p

  • 归零率:p ⊕ p = 0


代码如下

/*
 * 因为数组中只有两个数是不相同的,其余相同
 * 所以将整个数组的元素都取异或,由于异或的结合律,无先后顺序
 * 所以最终相同的一对异或成0,最终结果就是两个不同数的异或结果
 * 
 * 相同的数在每一位都是相同的,所以我们要从低位向高位找到
 * 两个不同的数是从哪一位开始出现不相同的情况,就是下文的mark的作用
 * 
 * 找到mark后,遍历原数组,用“&”对所有元素在该位置上鉴别
 * 分类标准是取与后为0或为1。
 * 同理在鉴别过程中,相同的数在mark位上一样也是相同的,取异或只会等于0
 * 
 * Code by Java
 */
class Solution {
	public int[] singleNumbers(int[] nums) {
		int sum = 0;			//将所有的数都取异或
		
		for (int num : nums) {
			sum ^= num;
		}
		
		int mask = 1;			//获取sum中最低位的1;
		
		while((sum & mask) == 0) {
			mask <<= 1;			//在该位是0,则mask左移一位
		}
		
		int a = 0, b = 0;		//用于表示数组中不同的两个数
		
		for (int num : nums) {
			if((num & mask) == 0) {
				a ^= num;		//0与任何数取异或都等于任意数本身
			} else {
				b ^= num;		//同理找到另一个数
			}
		}
		return new int[] {a,b};
	}
//	public static void main(String[] args) {
//		int[] aa = new int[] {1,2,3,10,2,2,1,3};
//		Solution sol = new Solution();
//		int[] kk = sol.singleNumbers(aa);
//		for (int i : kk) {
//			System.out.println(i);
//		}
//	}
}