算法-数组中只出现一次的数字

1. 找出数组中只出现一次的数字

这个题目其实有两种形式:

  1. 一个整型数组里除了某一个数字之外,其他的数字都出现了两次,找出这个只出现了一次的数字
    如数组 [1,2,2,1,3], 则目标数字为 3

  2. 一个整型数组里除了某两个数字之外,其他的数字都出现了两次,找出这两个只出现了一次的数字
    如数组 [1,2,2,1,3,5], 则目标数字为 3,5

2. 解法

2.1 只有一个不重复数字

思路:使用异或运算符^,0与其他数字异或的结果是那个数字,相等的数字异或得 0

  • 数组中除了某一个数字只出现了一次之外,其他数字都出现了两次,所以可定义一个变量赋初始值为0,用这个变量与数组中每个数字做异或运算,并将这个变量值更新为那个运算结果,直到数组遍历完毕,最后得到的变量的值就是数组中只出现了一次的那个数字
 public static int findOnceFrom2(int[] a) {
        int len = a.length, res = 0;
        for (int i = 0; i < len; i++) {
            res = res ^ a[i];
        }
        return res;
    }

2.2 有两个不重复的数字

这个问题其实是基于以上问题的扩展,首先可知当只有一个数出现一次时,把数组中所有的数依次异或运算,最后剩下的就是落单的数,因为成对出现的都抵消了。

  • 按照这个思路,首先还是先异或,最后剩下的数字肯定是A、B异或的结果 C,以数组 [1,2,2,1,3,5]为例, 则 A=3(0011),B=5(0101),结果C=6(0110)。C 的二进制表示中 1 所在的位,其实就是A 和 B 的二进制表示中数值不同的位。我们取第一个1 所在的位数 index,可知是(0010 = 1<<index)即 index=1据此把原数组分成两组,分组标准是数字第2位是否为1。这样成对的数字肯定在一个组中,因为相同数字所有位的数值都相同,而不同的数肯定不在同一组。之后把这两个组按照最开始的思路,依次异或,剩下的两个结果就是这两个只出现一次的数字
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {  
		 if(array == null || array.length <= 1){
	            num1[0] = num2[0] = 0; // 初始化为 0
	            return;
	        }
	        int len = array.length, index = 0, sum = 0;
	        for(int i = 0; i < len; i++){
	            sum ^= array[i];
	        }
	        for(index = 0; index < 32; index++){
	            if((sum & (1 << index)) != 0) break; // 获取第一个 1 所在位数 index
	        }
	        for(int i = 0; i < len; i++){
	            if((array[i] & (1 << index))!=0){ // 根据 index 将数组分为两部分
	                num2[0] ^= array[i];
	            }else{
	                num1[0] ^= array[i];
	            }
	        }
	        System.out.println(num1[0]+" "+num2[0]);
	        
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章