LeetCode上的一道题目:153. 寻找旋转排序数组中的最小值
来源:
https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/solution/xun-zhao-xuan-zhuan-pai-lie-shu-zu-zhong-de-zui-xi/
题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请找出其中最小的元素。
你可以假设数组中不存在重复元素。
示例 1:
输入: [3,4,5,1,2]
输出: 1
示例 2
输入: [4,5,6,7,0,1,2]
输出: 0
方法:二分查找
思路
一种暴力的解法是搜索整个数组,找到其中的最小元素,这样的时间复杂度是 $O(N)$ 其中 $N$ 是给定数组的大小。
一个非常棒的解决该问题的办法是使用二分搜索
。在二分搜索中,我们找到区间的中间点并根据某些条件决定去区间左半部分还是右半部分搜索。
由于给定的数组是有序的,我们就可以使用二分搜索。然而,数组被旋转了,所以简单的使用二分搜索并不可行。
我们希望找到旋转排序数组的最小值,如果数组没有被旋转呢?如何检验这一点呢?
如果数组没有被旋转,是升序排列,就满足 last element > first element
。
上图例子中 7 > 2
。说明数组仍然是有序的,没有被旋转。
上面的例子中 3 < 4
,因此数组旋转过了。这是因为原先的数组为 [2, 3, 4, 5, 6, 7]
,通过旋转较小的元素 [2, 3]
移到了后面,也就是 [4, 5, 6, 7, 2, 3
]。因此旋转数组中第一个元素 [4]
变得比最后一个元素大。
这意味着在数组中你会发现一个变化的点,这个点会帮助我们解决这个问题,我们称其为变化点
。
在这个改进版本的二分搜索算法中,我们需要找到这个点。下面是关于变化点
的特点:
所有变化点左侧元素 > 数组第一个元素
所有变化点右侧元素 < 数组第一个元素
算法
找到数组的中间元素
mid
。如果
中间元素 > 数组第一个元素
,我们需要在mid
右边搜索变化点。如果
中间元素 < 数组第一个元素
,我们需要在mid
做边搜索变化点。
上面的例子中,中间元素6
比第一个元素4
大,因此在中间点右侧继续搜索。
当我们找到变化点时停止搜索,当以下条件满足任意一个即可:
nums[mid] > nums[mid + 1]
,因此mid+1是最小值。nums[mid - 1] > nums[mid]
,因此mid是最小值。
在上面的例子中,标记左右区间端点。中间元素为2
,之后的元素是7
满足7 > 2
也就是nums[mid - 1] > nums[mid]
。因此找到变化点也就是最小元素为2
。
1 | class Solution { |
时间复杂度分析
- 时间复杂度:和二分搜索一样$O(logN)$
- 空间复杂度:$O(1)$
或者
判断最小的数是否在第一个位置,若是则返回
nums[0]
;否则,选取中间位置mid的数和right位置的数进行比较,若
nums[mid] < nums[r]
,说明最小的数在mid之前,right = mid
;反之,令left = mid + 1
;重复进行,直到
left >= right
。
1 | int findMin(int* nums, int numsSize){ |
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏