剑指Offer(56_1)数组中数字出现的次数

目录

数组中数字出现的次数

示例 1

示例 2

限制

方法一:哈希表

 方法二:位运算


数组中数字出现的次数

一个整型数组 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]

限制

2 <= nums.length <= 10000.

方法一:哈希表

因为需要剔除重复的元素,第一时间就想到了哈希表。

class Solution {
    public int[] singleNumbers(int[] nums) {
        int res[]=new int[2];
        HashMap map=new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i])){
                map.remove(nums[i]);
            }else{
                map.put(nums[i],1);
            }
        }
        int i=0;
        for (Integer num:map.keySet()) {
            res[i++]=num;
        }
        return res;
    }
}

剑指Offer(56_1)数组中数字出现的次数_第1张图片

 

 方法二:位运算

位运算中有个异或操作,可以判断两个数字是否相同,相同则结果为0,并且0和任何数n异或结果都为n。

异或操作也满足交换律,所以运算结果和数字的位置无关。

如果只有一个数字出现一次,其余数字出现两次,我们可以直接通过异或操作获得该数字x,

假设数组nums=[a,a,b,b,...,x],对所有数字进行异或操作

a\oplus a \oplus b \oplus b \oplus ... \oplus x=0\oplus 0\oplus ...\oplus x=x

但是本题有两个只出现一次的数字,所以我们的思路是分组进行异或,分别找到两个出现一次的元素。

假设数组nums=[a,a,b,b,...,x,y],两个不同的元素为x和y,

分组的精髓在于x和y的二进制至少有一位不同(分别为0和1),所以可以根据这一位的不同将数组拆分为两个数组,而两个子数组里面都是只包含一个出现一次的数字,其他都是出现两次的数字。

那么如何确定是哪一位不同呢?我们可以利用与运算(&)

首先我们将nums数组都进行异或操作,最后得到x \oplus y,这是一个二进制数,从右往左的第一个1就是x和y不同的位数。

  • x \oplus y&0001=1,那么x \oplus y的第一位为1
  • x \oplus y&0010=1,那么x \oplus y的第二位为1
  • ...

所以我们可以通过按位与(&)运算获取第一个为1的位数,由此将数组分为两个子数组,然后求解。

class Solution {
    public int[] singleNumbers(int[] nums) {
        int x = 0, y = 0, n = 0, m = 1;
        for(int num : nums)               // 1. 遍历异或
            n ^= num;
        while((n & m) == 0)               // 2. 循环左移,计算 m
            m <<= 1;
        for(int num: nums) {              // 3. 遍历 nums 分组
            if((num & m) != 0) x ^= num;  // 4. 当 num & m != 0
            else y ^= num;                // 4. 当 num & m == 0
        }
        return new int[] {x, y};          // 5. 返回出现一次的数字
    }
}

剑指Offer(56_1)数组中数字出现的次数_第2张图片

你可能感兴趣的:(#,剑指offer,哈希表,位运算,异或,按位与)