【leetcode】540.有序数组中的单一元素
这道题是很久以前的快手CPP面经中出现的,在此记录一下咋写
https://www.nowcoder.com/discuss/353156663853129728?sourceSSR=users
题目
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n)
时间复杂度和 O(1)
空间复杂度。
1 | 示例 1: |
思路
这道题如果用暴力遍历的话,O(N)
的时间复杂度很容易搞定,比如遍历一遍用map记录一下每个元素出现的次数,再遍历一遍map就能得到结果。
但是题目要求是用O(log N)
的时间复杂度,这就没有办法直接遍历了。但题目中给出的数组是有序的,再加上O(log N)
的时间复杂度,这就需要我们能想到用二分法来解决这道题。
现在确定是用二分法了,具体怎么二分呢?这又不是比大小找元素!
先观察一下给出的数组,以示例一为例:
1 | [1,1,2,3,3,4,4,8,8] |
将这个数组中的2补全,即所有元素都出现两次
1 | [1,1,2,2,3,3,4,4,8,8] |
能发现一个规律:奇数下标上的数和前一个数相同,偶数下标上的数和后一个数相同。
那么对于不符合条件的数组,我们只需要判断mid(数组中间)的元素
- 如果mid是奇数,判断它是否和前一个数相同,如果相同,则能确定只出现一次的数是在mid的后边,不同则在mid之前;
- 如果mid是偶数,判断它是否和后一个数相同,如果相同,则能确定只出现一次的数是在mid的后边,不同则在mid之前;
思路确定了,就可以写代码了
代码1-if/else
这里用if/else实现上述思路比较好理解
1 | class Solution { |
代码2-位运算
使用位运算可以统一的处理奇数和偶数,代码能更加简洁。使用异或运算(相异为一相同为零):
- 奇数异或1等于奇数减一(奇数末尾为1,异或1后末尾为0,相当于减一)
- 偶数异或1等于偶数加一(偶数末尾为0,异或1后末尾为1,相当于加一)
这样能写出如下代码,直接确定mid应该和谁进行比较
1 | class Solution { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 慕雪的寒舍!
评论