有序数组中的单一元素——二分查找、异或位运算


题目

给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。

请你找出并返回只出现一次的那个数。

你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。

解法一:二分查找

因为本题目有时间复杂度的要求,因此使用二分查找的方法解决。
当取得mid索引后有三种情况:

  1. nums[mid-1]!=nums[mid]且nums[mid+1]!=nums[mid],mid即为单一元素。
  2. nums[mid-1]==nums[mid]
    此时需要判断mid与right之间的元素个数right-mid,如果right-mid为偶数,则单一元素在left与mid-1之间。
  3. nums[mid+1]==nums[mid]
    此时需要判断mid与left之间的元素个数mid-left,如果mid-left为偶数,则单一元素在mid+1与right之间。
class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]==nums[mid+1]){
                if((mid-left)%2==0){
                    left=mid+2;
                }else
                    right=mid-1;
            }else if(nums[mid]==nums[mid-1]){
                if((right-mid)%2==0){
                    right=mid-2;
                }else
                    left=mid+1;
            }else   
                return nums[mid];
        }
        return nums[right];
    }
};

解法二:位运算的二分查找

假设x为单一元素,则x左右两边都有偶数个元素。当nums[mid]为x左边元素时需要满足的条件为:

  1. 当mid为偶数时,nums[mid]==nums[mid+1]
  2. 当mid为奇数时,nums[mid]==nums[mid-1]
    因此,当nums[mid]满足以上条件时,说明单一元素在mid的右边,否则在mid的左边。
    实际上并不需要判断mid的奇偶性,根据异或的性质,我们可以得到:
    当 m i d 为 偶 数 时 , m i d + 1 = m i d ⊕ 1 当mid为偶数时,mid+1=mid\oplus1 midmid+1=mid1
    当 m i d 为 奇 数 时 , m i d − 1 = m i d ⊕ 1 当mid为奇数时,mid-1=mid\oplus1 midmid1=mid1
class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int left=0,right=nums.size()-1;
        while(left<right)
        {
           int mid=left+(right-left)/2;
           if(nums[mid]==nums[mid^1])
                left=mid+1;
            else
                right=mid;
        }
        return nums[left];
    }
};

解法三:偶数下标的二分查找

假设x为单一元素,则x左边有偶数个元素,如果mid为偶数,则nums[mid]==nums[mid+1]成立。
我们只需要对偶数下标进行二分查找,初始left=0,right=nums.size()-1;
当二分查找过程中mid为奇数时,mid-=1保证mid为偶数。如果满足nums[mid]==nums[mid+1],则x在mid的右边,否则x在mid的左边。
在查找过程中,并不需要对mid的奇偶性进行进行判断,当mid为偶数时,mid&1=0,当mid为奇数时,mid&1=1。
因此在得到mid值之后,mid减去mid&1即可保证mid为偶数,如果mid为偶数,mid-mid&1值不变;如果mid为奇数,mid-mid&1将mid减一变为偶数。

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int left=0,right=nums.size()-1;
        while(left<right)
        {
           int mid=left+(right-left)/2;
           mid-=mid&1;
           if(nums[mid]==nums[mid+1])
                left=mid+2;
            else
                right=mid;
        }
        return nums[left];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值