剑指Offer-38 数组中的单身贵族(位运算)

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

集合法

其实,我觉得使用HashSet挺好的,时间复杂度也可以接受。
遍历数组

  1. 如果数不在集合中,添加到集合中
  2. 如果数在集合中,从集合中去掉
    遍历完成之后,数组中只剩下了两个数,也就是要求的单身数。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.*;

public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        Set<Integer> set = new HashSet<>();
        for(Integer i : array){
            // HashSet 时间复杂度为O(1)
            if(set.contains(i)) set.remove(i);
            else set.add(i);
        }
        ArrayList<Integer> list = new ArrayList<>(set);
        num1[0] = list.get(0);
        num2[0] = list.get(1);
    }
}

位运算

这个需要对Java位运算有一定的熟悉。
异或: 1000 XOR 1101 = 0101 相同为0,不同为1
与:1000 & 1100 = 1000 同时为1 的时候为1,否则为0
对于这一题:

  1. 把所有的数字亦或一下,相同的数字亦或后全部变成了0,相当于只把两个不同的数异或了。
  2. 两个不同数字亦或结果肯定不为0,找到结果中不为0的位。
  3. 对于整个数组,根据该位是否为0分为两组。每组异或即可得到结果。
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int sum = 0;
        for(int i : array) sum ^= i; // 所有数字异或
        int flag = 1; // 此时flag最低位为1
        while((sum & flag) == 0) flag <<=1; // 寻找标志位
        for(int i : array){
            if((i & flag) == 0) num1[0] ^= i; // 标志位为0组
            else num2[0] ^= i;// 标志位为1组
        }
    }
}
    原文作者:北国雪WRG
    原文地址: https://www.jianshu.com/p/d591b625d9d6
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞