算法小知识-------02·14-------有序数组中的单一元素

92 阅读1分钟

这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战

有序数组中的单一元素

该题出自力扣的540题 —— 有序数组中的单一元素【中等题】

审题

给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。

  • 其实这道题有做过类似的前身,不过是简单题,也是找出数组中单一元素;
    • 当时用的是异或实现
      int result = 0;
      for(int i =0;i<nums.lenth;i++){
          result ^=nums[i];
      }
      
    • 因为用的是for循环,所以不适合当前的解决方案 —— 时间复杂度O(log n)
  • 需要符合的话,要用到二分
    • 利用二分查找,时间复杂度可以满足O(log n)
    • 二分的话,需要找到相关的规律
      • 正常的数组 (所有的值都是双份) ,第一个出现的下标为偶数,第二个出现的下标为奇数
      • 二分查找的话,正常的一边也会遵循上述的规定;如果出现了单数的一边则会相反
      • 情况需要区分,mid值为奇书还是偶数
    • 如果mid为奇数,则需要以mid -1 对比
    • 如果mid 为偶数,则需要与 mid +1 对比
  • 还可以有相关的技巧
    • 例如二分的mid值计算
      • 常规的是 ( left + right )/2
      • 这样的话存在问题,如果用int 作为类型,会存在数值溢出,也就是数值十分大的时候
      • 可以用 left + (right - left) /2 去实现,可以避免溢出
      • 当然了,也可以直击底层,把 /2这个步骤也替换掉 —— left + ((right -left) >> 1)
  • 时间复杂度 O(log n)
  • 空间复杂度 O(1)

编码

class Solution {
   public int singleNonDuplicate(int[] nums) {
      int left =0,n = nums.length,right = n-1;
      while (right>left){
          int mid = left + ((right - left) >> 1);
           if(nums[mid] == nums[mid ^ 1])left = mid +1;
           else right = mid;
   }
   return nums[right];
}
}

image.png