有序数组中的单一元素

129 阅读2分钟

题目描述


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

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

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

 

示例 1:

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

示例 2:

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

 

提示:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 105

题目解释

解法1 暴力解决

空间复杂度为: O(n) > O(log n) 不符合题意

但实际执行时间好像跟解法2 差不多

/**
 * @param {number[]} nums
 * @return {number}
 */
var singleNonDuplicate = function(nums) {
   
    let i = 0 ,tmp = nums[0];
    for(var num of nums){
        if(num != tmp){
            if(i == 1){
                return tmp;
            }
            tmp = num;
            i = 1;
        }else{
            i++;
        }
    }

    return tmp
};

image.png

解法2 二分法

因为每个元素都会出现两次,唯有一个数只会出现一次。

所以数组一定是奇数

按常规的方法要去查看中间元素与前一个元素一致 还是与后一个一致 这样相当于多比较了一次

这边用了异或

异或:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

则:

0 ^ 1 = 1

1 ^ 1 = 0

2 ^ 1 = 0010 ^ 0001 = 0011 = 3

3 ^ 1 = 0011 ^ 0001 = 0010 = 2

4 ^ 1 = 0100 ^ 0001 = 0101 = 5

5 ^ 1 = 0101 ^ 0001 = 0100 = 4

在递增序列里,并且每个元素都会出现两次,则最理想的情况是 [0,1] [2,3] [4,5] ,这样就不用分别去与前后元素对比了。

如果在每队数据里,2个元素都相等,则单数出现在后面的数据里

否则单数出现在前面的数据里。

var singleNonDuplicate = function(nums) {
  
   let low = 0,hight = nums.length - 1;
   while(low < hight){
       let mid =  parseInt((hight + low)/2);
       if(nums[mid] == nums[mid ^ 1]){
           low = mid + 1
       }else{
           hight = mid 
       }
   }
   return nums[low];
};

image.png