剑指 Offer 56 - I. 数组中数字出现的次数【位运算】

剑指 Offer 56 - I. 数组中数字出现的次数

题目描述:
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

示例2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

public class JianZhiOffer56 {
	
	//测试
	public static void main(String[] args) {
		
		int[] arr = new int[] {4,1,4,6};
		
		int[] res =  singleNumbers(arr);
		
		for(int curr : res) {
			System.out.println(curr);
		}
	}
	
	// 剑指 Offer 56 - I. 数组中数字出现的次数
	// 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。
	// 请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
	// 异或运算:  0^N = N  , N^N = 0 ,  (N^B)^C =N^(B^C) , N^A^N = N^N^A = A 
	public static int[] singleNumbers(int[] nums) {
		
		// 返回的结果数组
		int[] res = new int[2];
	
		// N 异或 数组中的所有数 
		// 由题可知 ,只有两个数字出现一次,那么假设这两个只出现一次的数字为 x 和 y
		// 最后异或出来的结果是 N = x^y
		int N = 0;  
	
		for(int curr : nums) {
			// N 异或 数组中的所有数 
			 N ^= curr;
		}
		
		// 接下来的问题是如何将 x 和 y 分开, 可以根据 x != y ,那么 x 和 y 必定有一位不同,必定一个为 0,另一个为 1 ;
		// 假设 x 与 y 不同的位置是z , 那么 N 在z位置上的数字必定为 1 ;  异或规则 : 相同为0,不同为1;
		
		
		// 找到某个为1的位置z
		// 得到最右侧的 1
		// N 和 N取反加1 进行与运算
		int z = N & (~N + 1) ;
		
		// 另设一个变量K,对z位置上为0 或 为1 的所有数字进行异或运算 , 那么最后得到的一定是 x 或者y 中的某一个
		// 因为 x 和 y 在 z位置不同, 所有不可能同时存在于 z位置上为0的所有数字中 ,也不可能同时存在于 z位置上为 1的所有数字中 
		int K = 0;  
		
		for(int curr : nums) {
			// z位为0 的数
			if((z & curr) == 0) {
				//最后K = x 或者 K = y
				K ^= curr;
			}
		}
		
		res[0] = K ;
		
		//假如 K = x  , 又知 N = x ^ y ,那么 x ^ x ^ y = y ; K = y 同理
		res[1] = K ^ N;
		
		return res;
	}
}
	
	 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值