# 给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
#
# 请你找出并返回只出现一次的那个数。
#
# 你设计的解决方案必须满足 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 <= 10⁵
# 0 <= nums[i] <= 10⁵
#
# Related Topics 数组 二分查找 👍 410 👎 0
# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
low, high = 0, len(nums) - 1
while low < high:
mid = (low + high) // 2
if nums[mid] == nums[mid ^ 1]:
low = mid + 1
else:
high = mid
return nums[low]
# leetcode submit region end(Prohibit modification and deletion)
参考了官网解法。在此记录学习一下。
要注意审题,本题是有序列表,并要求O(log(n))的复杂度,应该用二分法,而不是逐个异或。
应该自己列出几种场景,找出规律:
初始化low=0, high = n - 1;
令 mid = (low + high) // 2,注意不是 (high - low) // 2 。
- 如果mid是奇数,且nums[mid] == nums[mid-1],那么单独的数应该在右侧;
- 如果mid是奇数,且nums[mid] == nums[mid+1],那么单独的数应该在左侧;
- 如果mid是偶数,且nums[mid] == nums[mid-1],那么单独的数应该在左侧;
- 如果mid是偶数,且nums[mid] == nums[mid+1],那么单独的数应该在右侧;
细节1
官方题解用了巧妙的对比:
if nums[mid] == nums[mid ^ 1]:
mid为奇数,mid ^ 1 = 0 = mid - 1;
mid为偶数,mid ^ 1 = 1 = mid + 1;
上面的比较为真,对应第1、4种情况,在右侧,应该更新low;
上面的比较为真,对应第2、3种情况,在左侧,应该更新high;
细节2
if nums[mid] == nums[mid ^ 1]:
low = mid + 1
else:
high = mid
更新low时,置为 mid + 1;
更新high时,置为 mid;
这样最后所得的结果就是 nums[low]。