《剑指 Offer》专项突破版 - 面试题 70 : 排序数组中只出现一次的数字(C++ 实现)

文章介绍了如何在有序数组中找到唯一出现一次的数字,首先通过异或操作确定唯一数字,然后利用数组排序特性采用二分查找优化解决方案。通过比较相邻元素和调整边界,实现时间复杂度为O(logn)的查找过程。
摘要由CSDN通过智能技术生成

题目链接LCR 070. 有序数组中的单一元素 - 力扣(LeetCode)

题目

在一个排序的数组中,除一个数字只出现一次之外,其他数字都出现了两次,请找出这个唯一只出现一次的数字。例如,在数组 [1, 1, 2, 2, 3, 4, 4, 5, 5] 中,数字 3 只出现了一次。

分析

如果将题目的条件稍稍改动,输入的数组没有经过排序,其他条件不变,那么这就是另一类很经典的面试题。由于两个相同的数字异或的结果是 0,因此如果将数组中所有数字异或,最终的结果就是那个唯一只出现一次的数字。我们需要计算数组中所有数字的异或,如果数组的长度为 n,那么这种解法的时间复杂度是 O(n)。

现在题目增加了一个条件,输入的数组是排序的,前面基于异或的解法仍然有效。但是面试官增加一个条件,可能是希望应聘者能够想出新的更好的解法。既然是在排序数组中查找某个数字,就尝试应用二分查找算法。

由于只出现一次的数字的左边有偶数个数字,因此它的下标 x 一定是偶数(下标从 0 开始),可以在偶数下标范围内二分查找。二分查找的目标是找到第一个 nums[x] nums[x + 1] 的偶数下标

可以将数组中的数字每两个分成一组,最初的若干组的两个数字都是相同的。但遇到只出现一次的数字之后,情况发生变化。这个只出现一次的数字和后面的数字结合成一组,导致后面所有组的两个数字都不相同。由此可见,只出现一次的数字正好是第一个两个数字不相同的分组的第 1 个数字

初始化,二分查找的左边界是 0,右边界是数组的最大偶数下标,即数组的长度减 1(因为数组的长度是奇数)。每次取左右边界的平均值 mid 作为判断的下标,如果 mid 是奇数,则将 mid 减 1,确保 mid 是偶数,然后比较 nums[mid] 和 nums[mid + 1] 是否相等,如果相等,则 mid < x,调整左边界;否则 mid >= x,调整有边界。调整边界之后继续二分查找,直到确定下标 x 的值

代码实现

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值