数组中只出现1次的数字

找出数组中只出现1次的数字。


问题1: 数组中其他元素出现几次?

问题2: 数组中的元素是否有序?

问题3: 数组是否可以修改?


如果要找出数组中只出现1次的数字,我们必须要知道数组中其他元素出现的次数,根据其他元素出现的次数我们可以使用不同的算法求解。

算法1: 使用HashMap记录各元素出现次数

首先介绍一种最简单最通用的算法就是用一个HashMap记录数组中各个元素出现的次数,然后找出出现1次的元素。

时间复杂度:O(n)

空间复杂度:O(n)

算法2: 逐个异或

如果题目中给出,数组中其他元素都出现2次,只有一个元素出现了1次,而且数组中的元素无序。那我们可以使用逐个异或的算法,只需遍历数组一遍,所有元素异或的结果就等于只出现1次的元素的值。

这种方法能够奏效的原理是:两个相同元素异或的结果是0,和0异或的结果还是元素本身,并且异或操作满足交换性,既不管异或的顺序是怎样,最终得到的结果都是一样的。

时间复杂度:O(n)

空间复杂度:O(1)

算法3: 二分查找

如果我们将题设条件再一次加强,既数组中其他元素出现2次,只有一个元素出现1次,并且数组中的元素有序。那我们就可以使用更加高效的算法。

mid = (start + end) / 2mid指向的是数组的中间元素,我们要保证mid前面正好有偶数个元素,既if(mid % 2 == 1) mid--;

1)如果重复1次的数字出现在前半部分或中间,则nums[mid]应该和后面一个数字不等,我们就在前半部分(包括总结元素)继续搜索。

2)如果重复1次的数字出现在后半部分,则nums[mid]应该和后面一个数字相等,我们就在后半部分继续搜索。

时间复杂度:O(logn)

空间复杂度:O(1)

算法4: 逐个异或+子数组划分

如果题目要求在一个乱序的数组中,有2个数字出现了1次,其他数字都出现了两次,要我们找到这两个数字。那么我们用算法2逐个异或数组中的元素,得到的就是这两个只出现一次的数字的异或结果。

为了能分别得到这两个数字,我们需要将原数组分组,分组的方法是使用两个数字异或结果中第一个为1的位对原数组进行分组(异或结果为1说明这两个数的二进制码在这个位置上是不同的),使这两个只出现1次的数字分别分到两个不同的组里,这样再对这两个组分别使用算法2,就可以得到这两个数字。

时间复杂度:O(n)

空间复杂度:O(1)

算法5: 位操作

如果题目中要求在一个乱序数组中,只有1个数字出现了1次,其他数组出现了3次,要我们找出这个只出现1次的数字target。那么我们除了使用算法1对数组元素出现的次数进行统计外,还可以使用位操作。

由于数组中其他数字都出现了3次,那么我们累加每个元素的第i位(i:0~31),如果累加结果能被3整除,说明target在这一位上是0,如果累加结果不能被3整除,说明target在这一位上是1,对32位进行累加对3取余后,我们就可以得到target。

时间复杂度:O(n)

空间复杂度:O(1)