【LeetCode-数组】有序数组中的单一元素

题目描述

给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
示例:

输入: [1,1,2,3,3,4,4,8,8]
输出: 2

输入: [3,3,7,7,10,11,11]
输出: 10

注意:
您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。

题目链接: https://leetcode-cn.com/problems/single-element-in-a-sorted-array/

思路1

将数组中的值进行异或,最终的结果就是只出现一次的数字。

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int ans = nums[0];
        for(int i=1; i<nums.size(); i++){
            ans ^= nums[i];
        }
        return ans;
    }
};

这种思路没有用到数组有序这个条件,而且时间复杂度为 O(n),不是题目要求的 O(log n)。

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

思路2

题目要求时间复杂度为 O(log n),这就在暗示我们使用二分查找来做。二分查找的关键点就是如何更新 left 和 right。假设当前查找的范围为 [left, right],mid = (left+right)/2。如果 mid 为偶数,则说明 mid 前面有偶数个数,例如 mid = 2,则 mid 前面有 2 个数(下标为 0, 1);如果 mid 为奇数,则说明 mid 前面有奇数个数。

如果 mid 为偶数,则 mid 前面有偶数个数,我们判断 nums[mid] 和 nums[mid+1] 是否相等。

  • 如果两者相等,则说明前面偶数个数字都是出现两次的数字。例如,数组为 [1,1,2,2,3],mid == 2 为偶数,nums[mid]==nums[mid+1]==2,所以 mid 前面的偶数个数字都出现了两次(两个 1),则出现一次的数字在 mid 右边,此时我们更新 left = mid + 1;
  • 否则,如果 nums[mid] 和 nums[mid+1] 不相等,则出现一次的数字在 mid 左边,此时更新 right = mid - 1。例如,数组为 [1,2,2,3,3],mid == 2,nums[mid]!=nums[mid+1], 1 在 mid 左边。

如果 mid 为奇数,则 mid 前面有奇数个数,我们同样判断 nums[mid] 和 nums[mid+1] 是否相等。

  • 如果两者相等,则说明只出现一次的数在 mid 左边,更新 right = mid - 1。例如,数组为 [1,2,2,3,3,4,4],mid == 3 为奇数,nums[mid]==nums[mid+1],所以 1 在 mid 左边。
  • 否则,如果两者不等,则说明只出现一次的数在 mid 右边,更新 left = mid + 1。例如,数组为 [1,1,2,2,3,3,4],mid==3,nums[mid]!=nums[mid+1],所以 4 在 mid 右边。

总结一下:

  • 首先判断 mid 的奇偶性,通过 mid 的奇偶性可以知道 mid 前有奇数个元素还是偶数个元素,然后通过 nums[mid] 和 nums[mid+1] 是否相等来缩小查找范围。
  • 如果 mid 为偶数:
    • 判断 nums[mid] 和 nums[mid+1] 是否相等:
      • 相等,则更新 left = mid + 1;
      • 不等,则更新 right = mid - 1;
  • 如果 mid 为奇数:
    • 判断 nums[mid] 和 nums[mid+1] 是否相等:
      • 相等,则更新 right = mid - 1;
      • 不等,则更新 left = mid + 1;

代码如下:

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int left = 0;
        int right = nums.size()-1;
        while(left<=right){
            int mid = left+(right-left)/2;
            if(mid%2==0 && mid+1<nums.size()){ // mid 为偶数
                if(nums[mid]==nums[mid+1]) left = mid+1;   // nums[mid]==nums[mid+1]
                else right = mid-1;
            }else if(mid%2!=0 && mid+1<nums.size()){  // mid 为奇数
                if(nums[mid]==nums[mid+1]) right = mid-1;  // nums[mid]==nums[mid+1]
                else left = mid+1;
            }else return nums[mid];  // 注意这一步说明 mid 为最后一个元素
        }
        return nums[left];  // 最后返回 nums[left]
    }
};
  • 时间复杂度:O(logn)
  • 空间复杂度:O(1)

参考

https://leetcode-cn.com/problems/single-element-in-a-sorted-array/solution/python3-qing-xi-si-lu-yong-shi-ji-bai-97nei-cun-ji/

原文地址:https://www.cnblogs.com/flix/p/13568355.html