每日一题,有序数组中的单一元素

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

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

你设计的解决方案必须满足 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. 初始化指针:设定两个指针 left 和 right,分别指向数组的起始和结束位置。
  2. 二分查找
    • 计算中间位置 mid
    • 检查 mid 是否是唯一的数:
      • 如果 mid 是偶数且 nums[mid] == nums[mid + 1],说明唯一的数在右半部分。
      • 如果 mid 是奇数且 nums[mid] == nums[mid - 1],也说明唯一的数在右半部分。
      • 否则,唯一的数在左半部分。
  3. 调整指针
    • 如果唯一的数在右半部分,将 left 移动到 mid + 1
    • 否则,将 right 移动到 mid
  4. 终止条件:当 left 和 right 相遇时,left 指向的就是唯一的数。

 代码实现

function singleNonDuplicate(nums) {
  let left = 0;
  let right = nums.length - 1;

  while (left < right) {
    let mid = Math.floor((left + right) / 2);

    // 检查 mid 是否是偶数
    if (mid % 2 === 0) {
      // 如果 mid 是偶数且 nums[mid] == nums[mid + 1],说明唯一的数在右半部分
      if (nums[mid] === nums[mid + 1]) {
        left = mid + 2; // 移动到右半部分
      } else {
        right = mid; // 移动到左半部分
      }
    } else {
      // 如果 mid 是奇数且 nums[mid] == nums[mid - 1],也说明唯一的数在右半部分
      if (nums[mid] === nums[mid - 1]) {
        left = mid + 1; // 移动到右半部分
      } else {
        right = mid; // 移动到左半部分
      }
    }
  }

  return nums[left];
}

// 测试用例
console.log(singleNonDuplicate([1, 1, 2, 3, 3, 4, 4, 8, 8])); // 输出: 2
console.log(singleNonDuplicate([3, 3, 7, 7, 10, 11, 11])); // 输出: 10

解释

  1. 初始化指针

    • left 和 right 分别初始化为数组的起始和结束位置。
  2. 二分查找

    • 计算中间位置 mid
    • 检查 mid 是否是偶数或奇数,并根据相邻元素的关系调整搜索范围。
    • 如果 mid 是偶数且 nums[mid] == nums[mid + 1],说明唯一的数在右半部分。
    • 如果 mid 是奇数且 nums[mid] == nums[mid - 1],也说明唯一的数在右半部分。
    • 否则,唯一的数在左半部分。
  3. 调整指针

    • 如果唯一的数在右半部分,将 left 移动到 mid + 1 或 mid + 2
    • 否则,将 right 移动到 mid
  4. 终止条件

    • 当 left 和 right 相遇时,left 指向的就是唯一的数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值