[2021校招必看之Java版《剑指offer》-40] 数组中只出现一次的数字

    技术2025-06-02  40

    文章目录

    1、题目描述2、解题思路2.1 哈希法2.2 位运算法 3、解题代码3.1 哈希法3.2 位运算法 4、解题心得

    1、题目描述

      【JZ40】一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。   知识点:数组,位运算,哈希   难度:☆

    2、解题思路

    2.1 哈希法

      使用一个哈希map来记录每一个数字重复的次数,然后把重复次数为1的输出即可。   具体步骤:   1、定义一个HashMap<Integer, Integer>;   2、遍历数组,记录每个数字的出现次数;   3、定义一个Queue,把出现次数为1的数字入队;   4、队列出队即最终结果。

    2.2 位运算法

      异或操作是:两个位,不同则为1,相同则为0。   具有以下规律:   1、n^0 = 0;   2、n^n = 0;   3、n^n^m = n^(n^m);满足交换律。   假设输入的数组array = {a,b,c,d,e,f,a,b,c,d},其中字母表示数字。把array每一个数字都异或:   int xor = a^b^c^d^e^f^a^b^c^d,根据交换律,等同于:   int xor = (a^a)^(b^b)^(c^c)^(d^d)^(e^f),等同于:   int xor = e^f   因此,数组所有数字进行异或的结果等同于不同的两个数字异或的结果。   下一步就是根据这个xor找出e和f分别是多少。   我们来分析这个xor,展开成二进制表示,肯定有些位为1,有些位为0。二进制的右侧为低位,左侧为高位。假设第3个位为1,那么可以推断:e和f的第3个二进制位肯定是一个为1,一个位0,不然异或结果不可能是1。   我们根据这个“第3个二进制位是否为1”作为条件,把array的数字分成两部分。那么,e和f肯定不会在一个部分里面,且相同数字肯定在一个部分里。   两部分数组分别为:arr1 = {a,a,c,c,e}和arr2 = {b,b,d,d,f}。   然后我们再分别把arr1和arr2异或一下:   int xot_arr1 = a^a^c^c^e 根据异或特性,得xot_arr1 = e;   int xot_arr2 = b^b^d^d^f 根据异或特性,得xot_arr2 = f;   即e和f都找到了。

    3、解题代码

    3.1 哈希法

    package pers.klb.jzoffer.medium; import java.util.*; /** * @program: JzOffer2021 * @description: 数组中只出现一次的数字 * @author: Meumax * @create: 2020-07-04 10:37 **/ public class NumsAppearOnce { // num1,num2分别为长度为1的数组。传出参数 // 将num1[0],num2[0]设置为返回结果 public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { HashMap<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < array.length; i++) { if (map.containsKey(array[i])) { map.put(array[i], map.get(array[i]) + 1); } else { map.put(array[i], 1); } } Queue queue = new LinkedList(); Set<Integer> set = map.keySet(); for (Integer key : set) { if (map.get(key) == 1) { queue.add(key); } } num1[0] = (Integer) queue.poll(); num2[0] = (Integer) queue.poll(); } }

      时间复杂度:O(N)   空间复杂度:O(N)

    3.2 位运算法

    package pers.klb.jzoffer.medium; /** * @program: JzOffer2021 * @description: 数组中只出现一次的数字(位运算法) * @author: Meumax * @create: 2020-07-04 10:37 **/ public class NumsAppearOnce { // num1,num2分别为长度为1的数组。传出参数 // 将num1[0],num2[0]设置为返回结果 public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { int xor = 0; for (int i : array) { xor ^= i; } int index = 1; // xor从右到左第一个为1的位置 while ((index & xor) == 0) { index = index << 1; } int result1 = 0; int result2 = 0; for (int j : array) { if ((index & j) == 0) { result1 ^= j; } else { result2 ^= j; } } num1[0] = result1; num2[0] = result2; } }

      时间复杂度:O(N)   空间复杂度:O(1)

    4、解题心得

      类似这种找相同或找不同的数字,哈希法往往是最简单快捷的,笔试中优先考虑。在面试中,如果能够想出位运算的,说明基本功扎实,能给自己加分。

    Processed: 0.012, SQL: 9