LeetCode 每日一题 - 2022/2/14 (540. 有序数组中的单一元素)

7 篇文章 0 订阅
5 篇文章 0 订阅
这篇博客介绍了如何在一个有序整数数组中,找到只出现一次的数字。方法是利用二分查找和位运算,通过O(logn)时间复杂度和O(1)空间复杂度来实现。在二分查找过程中,根据mid的奇偶性和相邻元素的关系更新搜索范围,最终找到目标数字。
摘要由CSDN通过智能技术生成

描述

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

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

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

思路

  题目指出重复的数字只会出现两次,且数组有序,故含有单一元素的部分必然含有 2n - 1 个数,再如下分析:
LeetCode 540分析
说明:当 mid % 2 = 0 时,更新规则为left = mid (或right = mid) 也可(后面为了契合改进的代码,使用 left = mid (right = mid) 更新规则);

边界分析:
  按图中的更新规则,范围会朝含有单一元素的部分缩小,边界情况下,会出现abb或bba的情况,此时再更新会将范围缩小至 a,所以在下一次迭代时判断是否为边界值 (0 或 nums.size()- 1)即可;

代码

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int n = nums.size() - 1;
        int left = 0, right = n, mid;
        while (left <= right) {
            mid  = (left + right) / 2;
            if (mid == 0 or mid  == n)
                return nums[mid];
            
            if (nums[mid] == nums[mid + 1])
                if (mid % 2 == 1)
                    right = mid - 1;
                else
                    left = mid;
            else if (nums[mid] == nums[mid  - 1])
                if (mid % 2 == 1)
                    left = mid + 1;
                else
                    right = mid;
            else 
                return nums[mid];
        }
        return 0;
    }
};

改进(参考LeetCode官方):
  利用按位异或的性质,可以得到 mid 和相邻的数之间的如下关系,其中 ⊕ 是按位异或运算符:

    当 mid 是偶数时,mid + 1 = mid ⊕ 1;
    当 mid 是奇数时,mid − 1 = mid ⊕ 1。

  且 nums[mid] = nums[mid ^ 1] 时都是更新 left,不过偶数情况下是 left = mid,奇数情况下是 left = mid + 1,此时可以利用与运算更新:

    left = mid + (mid & 1);

改进后的代码:

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int n = nums.size() - 1;
        int left = 0, right = n, mid;
        while (left <= right) {
            mid  = (left + right) / 2;
            if (mid == 0 or mid  == n or (nums[mid] != nums[mid - 1] and nums[mid] != nums[mid + 1]))
                return nums[mid];
            
            if (nums[mid] == nums[mid ^ 1])
                left = mid + (mid & 1);
            else
                right = mid - (mid & 1);
        }
        return 0;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值