题目描述
给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
示例:
输入: [1,1,2,3,3,4,4,8,8]
输出: 2
注意: 您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。
思路分析
「思路一」
由于每个元素都会出现两次,寻找只出现一次的元素,我们可以想到的是使用异或,我们可以利用异或的特性,相同为0,那么出现两次的结果都会被异或为0,剩下的那一位就是我们需要的结果。
「思路二」
到目前为止,题目所给的有序数组这一条件我们似乎并没有使用到,题目要求我们的时间复杂度应该是 O(log n),因此我们可以确定这道题需要使用二分查找。
我们使用二分查找,首先需要判断每一次二分后,中间元素在我们需要查找的元素的左边还是右边。我们可以发现这样的一些规律:
1、在只出现一次的数之前,其偶数位的元素与后一位元素相同,奇数位的元素与前一位元素相同。
2、在只出现一次的数之后,其奇数位的元素与后一位元素相同,偶数位的元素与前一位元素相同。
3、如果某个元素和其前一位元素以及后一位元素都不相同,那么这个元素就是我们所要查找的 “单个元素”。
因此,我们每次取得中间元素,可以使用中间元素所处的奇偶位,以及该元素与之前、之后元素的关系,来判断这个中间元素在 “单个元素” 之前或者之后。
代码描述
下面使用 Java 对思路二进行代码描述:
class Solution {
public int singleNonDuplicate(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (mid == 0 || nums[mid] != nums[mid - 1] && nums[mid] != nums[mid + 1]) {
return nums[mid];
}
if ((mid & 1) == 1 && nums[mid] == nums[mid - 1] || (mid & 1) == 0 && nums[mid] == nums[mid + 1]) {
// 左指针向右移动
left = mid + 1;
} else {
right = mid - 1;
}
}
return nums[left];
}
}
欢迎关注
技术公众号:【小猿君的算法笔记】,一起学习,一起成长。