摘要:
二分查找经典应用,当数组中包含重复数字时,事情发生了变化。
题目
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
请找出其中最小的元素。
注意数组中可能存在重复的元素。
示例 1:
输入: [1,3,5]
输出: 1
示例 2:
输入: [2,2,2,0,1]
输出: 0
说明:
- 这道题是 LeetCode 153. 寻找旋转排序数组中的最小值 的延伸题目。
- 允许重复会影响算法的时间复杂度吗?会如何影响,为什么?
二分查找
这道题和 寻找旋转排序数组中的最小值 的区别就在于折叠数组中可能存在重复。
什么时候会产生影响呢?那就是当折叠点在原数组中某一数字相同段内时,折叠之后,数组首尾相同。那么,如果 mid
更新到与数组首尾相同的数字时,我们无法利用二分查找所依赖的 性质 确定 mid
是在左半边还是右半边。
那么,解题思路就是:
- 先特判非单调递减情况,排除原数组折叠点在数组下标范围外的情况。
- 再特判折叠数组首尾相同的情况,方法是移动右指针向左直到和左端点不同为止。那么此时又有两种情况:
- 右半边全为与左端点相同的数字,那么此时右指针移到了左半边,
nums[hi] > nums[0]
- 右半边不全是与左端点相同的数字,那么此时右指针依然在右半边,
nums[hi] < nums[0]
- 对于以上情况1,直接返回数组首即可;而对于情况2,需要按照传统二分查找,找到右半边的左边界。详情请参考: 寻找旋转排序数组中的最小值
另外可以想一下,如果折叠数组数组完全相同,也就是最坏的情况,会怎么样。
那必然是最终右指针左移时与左指针相遇,进行一次常规二分直接得出答案。当然也可以在进入常规二分之前特判一下,都无所谓。
最坏的情况下,复杂度为 $O(N)$,平均的情况下,复杂度为 $O(logn)$.
1 | // 执行用时: 4 ms |
1 | // 执行用时: 0 ms |