给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
示例:
输入: [1,1,2,3,3,4,4,8,8]
输出: 2
输入: [3,3,7,7,10,11,11]
输出: 10
注意:
您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。
题目链接: https://leetcode-cn.com/problems/single-element-in-a-sorted-array/
将数组中的值进行异或,最终的结果就是只出现一次的数字。
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int ans = nums[0];
for(int i=1; i<nums.size(); i++){
ans ^= nums[i];
}
return ans;
}
};
这种思路没有用到数组有序这个条件,而且时间复杂度为 O(n),不是题目要求的 O(log n)。
题目要求时间复杂度为 O(log n),这就在暗示我们使用二分查找来做。二分查找的关键点就是如何更新 left 和 right。假设当前查找的范围为 [left, right],mid = (left+right)/2。如果 mid 为偶数,则说明 mid 前面有偶数个数,例如 mid = 2,则 mid 前面有 2 个数(下标为 0, 1);如果 mid 为奇数,则说明 mid 前面有奇数个数。
如果 mid 为偶数,则 mid 前面有偶数个数,我们判断 nums[mid] 和 nums[mid+1] 是否相等。
[1,1,2,2,3]
,mid == 2 为偶数,nums[mid]==nums[mid+1]==2,所以 mid 前面的偶数个数字都出现了两次(两个 1),则出现一次的数字在 mid 右边,此时我们更新 left = mid + 1;[1,2,2,3,3]
,mid == 2,nums[mid]!=nums[mid+1], 1 在 mid 左边。如果 mid 为奇数,则 mid 前面有奇数个数,我们同样判断 nums[mid] 和 nums[mid+1] 是否相等。
[1,2,2,3,3,4,4]
,mid == 3 为奇数,nums[mid]==nums[mid+1],所以 1 在 mid 左边。[1,1,2,2,3,3,4]
,mid==3,nums[mid]!=nums[mid+1],所以 4 在 mid 右边。总结一下:
代码如下:
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
while(left<=right){
int mid = left+(right-left)/2;
if(mid%2==0 && mid+1<nums.size()){ // mid 为偶数
if(nums[mid]==nums[mid+1]) left = mid+1; // nums[mid]==nums[mid+1]
else right = mid-1;
}else if(mid%2!=0 && mid+1<nums.size()){ // mid 为奇数
if(nums[mid]==nums[mid+1]) right = mid-1; // nums[mid]==nums[mid+1]
else left = mid+1;
}else return nums[mid]; // 注意这一步说明 mid 为最后一个元素
}
return nums[left]; // 最后返回 nums[left]
}
};
原文:https://www.cnblogs.com/flix/p/13568355.html