剑指 Offer 11. 旋转数组的最小数字
思路
算法流程:
-
初始化: 声明 ii, jj 双指针分别指向 numsnums 数组左右两端;
-
循环二分: 设 m = (i + j) / 2m=(i+j)/2 为每次二分的中点( “/” 代表向下取整除法,因此恒有 i \leq m < ji≤m<j ),可分为以下三种情况:
- 当 nums[m] > nums[j]nums[m]>nums[j] 时: mm 一定在 左排序数组 中,即旋转点 xx 一定在 [m + 1, j][m+1,j] 闭区间内,因此执行 i = m + 1i=m+1;
- 当 nums[m] < nums[j]nums[m]<nums[j] 时: mm 一定在 右排序数组 中,即旋转点 xx 一定在[i, m][i,m] 闭区间内,因此执行 j = mj=m;
- 当 nums[m] = nums[j]nums[m]=nums[j] 时: 无法判断 mm 在哪个排序数组中,即无法判断旋转点 xx 在 [i, m][i,m] 还是 [m + 1, j][m+1,j] 区间中。解决方案: 执行 j = j - 1j=j−1 缩小判断范围,分析见下文。
-
返回值: 当 i = ji=j 时跳出二分循环,并返回 旋转点的值 nums[i]nums[i] 即可。
作者:jyd
链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/mian-shi-ti-11-xuan-zhuan-shu-zu-de-zui-xiao-shu-3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码
class Solution:
def minArray(self, numbers: List[int]) -> int:
i, j = 0 , len(numbers)-1
while i<j:
m = (i+j)//2
if numbers[j] > numbers[m]: j = m
elif numbers[j] < numbers[m]: i = m+1
else: j -= 1
return numbers[i]
分析
时间复杂度
O
(
log
2
N
)
O(\log_2 N)
O(log2N). 在特例情况下(例如 [1, 1, 1, 1][1,1,1,1]),会退化到 O(N)。
空间复杂度 O(1)O(1) : ii , jj , mm 变量使用常数大小的额外空间。