题目描述
给定一个只包含整数的有序数组 nums ,每个元素都会出现两次,唯有一个数只会出现一次,请找出这个唯一的数字。
示例1
输入: nums = [1,1,2,3,3,4,4,8,8]
输出: 2
示例2
输入: nums = [3,3,7,7,10,11,11]
输出: 10
思路1
第一种解法用常规的异或,异或的性质:同位相同为0,不同为1。那么两个相同的数字异或的结果就是0了。所以我们只需要扫描一遍数组,把所有的数都异或起来,最后的异或值就是只出现一次的那个数了。时间复杂度为O(n)
class Solution {
public int singleNonDuplicate(int[] nums) {
int ans = 0;
for(int num : nums){
ans ^= num;
}
return ans;
}
}
思路2
上一个思路虽然时间复杂度为O(n),已经算高效的了,但是依然不是最高效的解法,别忘了还有一个条件我们没用用到,有序数组。
看到有序,看到查找,我们可以想到用二分来做。
我们把所有数字进行分组,两个挨着的是一组,比如拿第二组 [3,3,7,7,10,11,11]来说,分好组就是(3,3) (7,7) (10,11) (11)
这样的话,在遇到单独出现的数字之前,前面的每个组里面的两个数字都是相同的,直到遇到单独出现的数组,后面所有的组也因为他的出现而都错开了位置,也变成了组内两个数字不相同,所以我们就需要找到第一个出现不同数字的那个组。
class Solution {
public int singleNonDuplicate(int[] nums) {
int l = 0, r = nums.length / 2;
//l和r表示组号,n个数字被分成n/2组,其中0~n-1组都是两个数字,第n组是一个数字
while(l <= r){
int mid = (l + r) / 2;
//i是第mid组第一个数字的下标
int i = mid * 2;
if(i < nums.length - 1 && nums[i] != nums[i + 1]){
//如果是第一组,因为左边没有组了,所以肯定是第一个出现不同的组
//如果不是第一组,但是他前面的那一个组两个数字相同,那么也可以说明他是第一组不相同的
if(mid == 0 || nums[i - 2] == nums[i - 1]){
return nums[i];
}
r = mid - 1;
}else{
l = mid + 1;
}
}
//如果前面的组都没出现不相同的组,那么结果就是最后那个自己一个组的数字
return nums[nums.length - 1];
}
}