只出现一次的数字问题

问题1

给定一整形数组,已知该数组中一个数出现了一次,其余的数出现了偶数次,找到这个出现一次的数

解法一:使用hashMap记录次数,然后返回只出现一次的那个数

代码如下:

    public int singleNumber(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int num : nums) {
            int val = map.containsKey(num) ? map.get(num) + 1 : 1;
            map.put(num, val);
        }
        for(int num : nums) {
            if(map.get(num) == 1) {
                return num;
            }
        }
        return 0;
    }

时间复杂度为O(N),额外空间复杂度O(N)

解法二:使用位运算。我们知道两个相同的数进行异或操作后的结果是0,任何数和0异或的结果是它本身,异或操作亦具有交换律。因此我们只需让数组中所有数异或到一起,结果即为所求。

代码如下:

    public int singleNumber(int[] nums) {
        int result = 0;
        for(int num : nums){
            result ^= num;
        }
        return result;
    }

时间复杂度O(N),额外空间复杂度O(1)。

问题2

给定一整型数组,已知其存在两个数出现了一次,其它数出现了偶数次,找到那连个出现一次的数。

该问题依然可以使用HashMap进行求解,解法与问题一相同,不加赘述了。

该问题中由于含有两个出现一次的数,如直接全部异或的到的结果为这两数的异或,因此无法直接按问题一解法求解。

一个想法是将这两个数分开,分别求解,我们知道若两数相同则其在任一位都相同,若两数不同,则总是存在一位不同的位。由于我们已经得到了这两数的异或记做XOR1,找到XOR1中为1的那一位,可得该位上这两数一定不同,因此可以通过该位是否为1可以将数组分为两块,分别对这两块求异或即为所求。

实现代码如下:

    public int[] singleNumber(int[] nums) {
        int xor1 = 0;
        for(int num : nums){
            xor1 ^= num;
        }
        int number = 0; // 存储为1的位数
        for(int i = 0; i < 32; i++){
            if((xor1 & 1) == 1){
                number = i;
                break;
            }
            xor1 = xor1 >> 1;
        }
        int val1 = 0, val2 = 0;
        for(int num : nums){
            if(((num >> number) & 1) == 1){
                val1 ^= num;
            }else{
                val2 ^= num;
            }
        }
        return new int[] {val1, val2};
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章