提示:使用二分查找降低时间复杂度。
文章目录
- 一、问题描述
- 示例
- 二、解题思路
- 三、代码实现
- 代码解析
- 总结
一、问题描述
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。
示例
示例一:
输入: nums = [1, 1, 2, 3, 3, 4, 4, 8, 8]
输出: 2
输入: nums = [3, 3, 7, 7, 10, 11, 11]
输出: 10
二、解题思路
要在 O(log n) 的时间复杂度内找到只出现一次的元素,我们可以利用有序数组的特性,使用二分查找。通过观察数组的结构,我们可以确定以下几个要点:
1.元素对的特性:
在有序数组中,成对出现的元素在偶数索引的位置上会形成一种“规则”。例如,当一个元素在偶数位置时,它的下一个元素(如果存在)应该是同一个元素。
而对于只出现一次的元素,定义一种特例,其位置会打破这一规则。
2.判断逻辑:
在任何时刻,我们可以通过比较 nums[mid] 和 nums[mid + 1] 的值来决定下一个搜索的区间。
如果 mid 是偶数,并且 nums[mid] 等于 nums[mid + 1],则只出现一次的元素一定在右半部分。反之,则在左半部分。
三、代码实现
代码如下:
class Solution:
def singleNonDuplicate(self, nums):
left, right = 0, len(nums) - 1
while left < right:
mid = left + (right - left) // 2
# 确保 mid 处于偶数位置,必要时调整
if mid % 2 == 1:
mid -= 1
# 检查 mid 和 mid + 1 的值
if nums[mid] == nums[mid + 1]:
left = mid + 2 # 只出现一次的元素在右侧
else:
right = mid # 只出现一次的元素在左侧
return nums[left] # left 和 right 将重合在只出现一次的元素上
# 使用示例
solution = Solution()
print(solution.singleNonDuplicate([1, 1, 2, 3, 3, 4, 4, 8, 8])) # 输出: 2
print(solution.singleNonDuplicate([3, 3, 7, 7, 10, 11, 11])) # 输出: 10
代码解析
1.初始化指针:
我们使用 left 和 right 指针来分别标识数组的起始和结束位置。
2.二分查找:
在 while 循环中进行二分查找,计算中间索引 mid。确保 mid 总是指向偶数位置。
3.判断与更新:
通过比较 nums[mid] 和 nums[mid + 1] 判断区间:
如果相等,说明左侧所有元素都是成对的,因此更新 left 为 mid + 2。
如果不等,说明只出现一次的元素在左侧,更新 right 为 mid。
4.返回唯一元素:
循环结束后,left 和 right 会重合在那个只出现一次的元素上。
总结
时间复杂度:O(log n),每次迭代时我们都将搜索空间减半。
空间复杂度:O(1),只使用了常量级别的额外空间。
通过使用二分查找方法,我们能够在有序数组中高效地找到只出现一次的元素。这种方法巧妙地利用了数组的有序性,将问题简化为更小的子问题,使得我们可以在比线性搜索更短的时间内得到结果。