欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数组之数组中只出现一次的数字

程序员文章站 2022-06-11 19:00:21
...

1.本题知识点

   位运算,异或

2. 题目描述

  一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

3. 思路

   这题考察的是异或操作,即对应位上值相同为0,值不同为1。
  ① 异或操作满足交换结合律,比如A ^ B ^ A = B ^ (A ^A) = B ^ 0 = B。所以,数组中数字两两异或,若其中有2个单次出现的数字,最后得到的结果就是这2个单次数字的异或结果,其他出现2次的数字都异或抵消掉了。
  ② 通过①的分析,假设数组中只有一个单次的数字,那么异或后的结果就是这个数,所以,考虑把原数组分开,通过什么分开呢?原数组异或结果位数为1的索引值,区分开2个单次的数,最后分别求2个子数组异或的结果即可。
   举例说明:

数组之数组中只出现一次的数字

   ③ 如何知道是哪个位上不同呢?比如上面是第n =3位不同,现在我们要找到这个n。
   方法:通过【原数组异或结果】【从后往前找到第一个1】的位置即可。
   举例:

数组之数组中只出现一次的数字

   Java版本:
package com.algorithm.array;

/**
 * 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
 * 时间复杂度O(n),空间复杂度O(1)
 * @author wxq
 *
 */
public class NumXOR {
	
	public static void main(String[] args) {

		int [] array = {2,4,3,6,3,2,5,5};
		int[] num1 = new int[array.length];
		int[] num2 = new int[array.length];
		findNumsAppearOnce(array, num1, num2);
		
		System.out.println(num1[0] + "  " + num2[0]);
	}
	
	/**
	 * 
	 * @param array
	 * @param num1 存放返回结果
	 * @param num2
	 */
	static void findNumsAppearOnce(int [] array,int num1[] , int num2[]){
		if(array == null || array.length == 0){
			num1[0] = -1;
			num2[0] = -1;
		}
		//1. 求原数组两两异或结果
		int bitResult = 0;
		for(int i =0 ; i < array.length; i++){
			bitResult ^= array[i];
		}
		
		//2. 找到倒数第一个1的位置
		int index = findFirst1(bitResult);
		
		//3. 根据index位上是不是1切分原数组,并将子数组两两异或。
		for(int i =0 ; i < array.length; i++){
			if(isBit1(array[i],index)){
				num1[0] ^= array[i];
			}
			else{
				num2[0] ^= array[i];
			}
		}
		
		//4. 最终得到单次出现数字num1[0] num2[0]
	}
	/**
	 * 找到原数组异或结果的倒数第一个1的位置
	 * @param bitResult
	 * @return
	 */
	static int findFirst1(int bitResult){
		int index = 0;
		while((bitResult & 1) == 0){
			bitResult >>= 1;
			index++;
		}
		
		return index;
	}
	
	/**
	 * 判断数字第index位置上是不是1
	 * @param target
	 * @param index
	 * @return
	 */
	static boolean isBit1(int target, int index){
		
		return ((target >> index) & 1) == 1;
	}
}