leetcode-540.有序数组中的单一元素
二分查找
题目详情
**给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n)
时间复杂度和 O(1)
空间复杂度。
示例1:
输入: nums = [1,1,2,3,3,4,4,8,8]
输出: 2
示例2:
输入: nums = [3,3,7,7,10,11,11]
输出: 10
我的first代码:
惯性思维想到的是依次比较每一个数和他后面的一个数,一旦不同就是前面这个数是单一的,但是这种方法有很多特殊情况都通过不了,且复杂度不满足要求
class Solution
{
public:
int singleNonDuplicate(vector<int>& nums)
{
int ji=0,ou=1,len=nums.size()-1;
if(len==0)
return nums[0];
while(ji<len)
{
if(nums[ji]!=nums[ou])
return nums[ji];
ji+=2;
ou+=2;
}
return 0;
}
};
第11个用例[1,1,2]
就无法通过,所以这种方法是不可行的
同样的我们可以利用二分查找,(寻找到一定规律):
例如示例一[1,1,2,3,3,4,4,8,8]
,我们把2补全后,[1,1,2,2,3,3,4,4,8,8]
可以看出偶数下标和奇数下标的值都是相等的,若有一个单一元素
则可通过二分查找,mid
若是偶数,则比较mid
与mid+1
,若是奇数,则比较mid
与mid-1
,详细代码如下:
class Solution
{
public:
int singleNonDuplicate(vector<int>& nums)
{
int l=0,r=nums.size()-1,mid;
while(l<r)
{
mid=(l+r)/2;
if(mid%2==0) //mid若是偶数
{
if(nums[mid]==nums[mid+1]) //mid和mid+1相等,则前面肯定是成双成对的
l=mid+1; //所以单一元素位于[mid+1,r]
else //若不相等,则位于[l,mid],例如示例一
r=mid;
}
else //mid是奇数
{
if(nums[mid]==nums[mid-1]) //mid和mid-1相等,则前面肯定是成双成对的
l=mid+1; //单一元素位于[mid+1,r]
else //否则位于[l,mid],例如示例二
r=mid;
}
}
return nums[r]; //最后肯定是从while跳出的,所以可以返回nums[l]
//或者nums[r]
}
};
涉及知识点:
1.二分查找
二分查找也常被称为二分法或者折半查找,每次查找时通过将待查找区间分成两部分并只取一部分继续查找,将查找的复杂度大大减少。对于一个长度为 O(n) 的数组,二分查找的时间复杂度为 O(log n)。