LeetCode 153. 寻找旋转排序数组中的最小值 二分题解,重新认识二分。
题目
153. 寻找旋转排序数组中的最小值
https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到: 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2] 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7] 注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
思路
这道题与 搜索二维矩阵 II 有一个共同点,那就是数据是保证了部分排序的,结合题干要求复杂度O(log n)
,我们可以尝试二分的思路。
二分的核心:每一轮遍历都可以丢弃一些不符合条件的数据,以此提高后续搜索的效率。
- 朴素二分:针对全局有序的数组,一次丢弃正好一半范围的数据;
- 树形
BST
二分:针对排列为树形的数组(二维数组、矩阵),一次可以丢弃一行或者一列的数据; - 旋转二分:针对本题这种大小区间不定的情形,一次可以丢弃一半范围的数据;
二分变体解
思路
复杂度分析
时间
O(logn)
时间复杂度。
空间
无额外空间占用,空间复杂度O(1)
。
代码
|
|
实际上这里代码可以适当简化,只比较右区间值nums[r]
与nums[mid]
即可判断出上图中的三种情况:
nums[r]
<nums[mid]
:说明mid
此时在旋转过的左区间,l
向右,l=mid+1
;nums[r]
>nums[mid]
:说明mid
在右区间,r
向左,r=mid
;
只使用nums[l]
与nums[mid]
比较,上图中的nums[l]
<nums[mid]
时无法决定挪动左右哪个区间。
简化代码:
|
|
154. 寻找旋转排序数组中的最小值 II
- https://leetcode.cn/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/
- https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array-ii/
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到: 若旋转 4 次,则可以得到 [4,5,6,7,0,1,4] 若旋转 7 次,则可以得到 [0,1,4,4,5,6,7] 注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中> 的 最小元素 。
二分解
关键需要画图分析用例情况。
思路
154相比153只改变了一个条件:元素可重复。对应循环中的判断新增了一种等值的情况:nums[r] == nums[mid]
。
用例分布分析:
- 无等值元素的情况下,153解法代码即可满足。
- 有等值元素的情况下
- 全部等值,不管怎么挪动区间都可以求解
- 如下图
我们再看个用例:[1011111]
上述两图的情况下,均满足:nums[r] == nums[mid]
,这种情况下如果收缩l
,上图的第一种情况就会出错,如果收缩r
,我们无法直接跳跃到mid
的位置,只能逐步收缩,即r=r-1
。
代码
|
|