LeetCode 153. 寻找旋转排序数组中的最小值
题目描述
已知一个长度为 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) 的算法解决此问题。
示例
示例 1:
输入:nums = [3,4,5,1,2] 输出:1 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
示例 2:
输入:nums = [4,5,6,7,0,1,2] 输出:0 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。
示例 3:
输入:nums = [11,13,15,17] 输出:11 解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。
解法
1.二分查找
解题思路
本题重点在于,如何利用二分。二分的思想在于,每次淘汰一半(记住这个思想,是所有二分题目的关键)。
基于这个思想,我们要去想淘汰策略。我们发现本题中,有:最小元素 m 的左边所有元素都比数组的最后一个元素 x大,右边所有元素(不含x)都比 x 小。于是我们的淘汰策略为:对于每一对low high,比较中间元素值和x的大小:
- nums[mid]<x:说明 mid 在 m 的右边,即目标 m 在 mid 的左边,故可淘汰右半边;
- nums[mid]>x:同理淘汰左半边;
- nums[mid]==x: 不可能,因为数组无重复值,如果成立,则必然有mid==n-1,则必然有low==high==n-1。但当low==high时,我们已经找到m
public int findMin(int[] nums) {int low = 0, high = nums.length - 1;int x = nums[high];while (low < high) { // 注意这里没有=了,=的时候直接退出循环得到答案int mid = (low + high) / 2;if (nums[mid] < x)high = mid; //这里不是常规的 mid-1 是因为此时的mid有可能就是我们要找的melselow = mid + 1; //这里和常规一样是 mid+1 是因为此时的mid不可能是m(他都比x大了噻怎么可能是最小的)}return nums[low];}时间复杂度:时间复杂度为 O(logn),其中 n 是数组 nums 的长度。在二分查找的过程中,每一步会忽略一半的区间,因此时间复杂度为 O(logn)。
空间复杂度:O(1)。
