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