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若是偶数,则比较midmid+1,若是奇数,则比较midmid-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)。

posted @ 2022-03-30 10:27  ggaoda  阅读(7)  评论(0编辑  收藏  举报  来源