寻找旋转排序数组中的最小值
一、题目描述
已知一个长度为 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、二分查找 O(logn)
数组在旋转前是有序的,因此可以考虑二分法。
数组在某个点旋转,分为左右两个区,两个区内元素是有序的。
首先初次查找范围是[left,right]
。
- 如果
nums[mid]>
最后一个元素,则nums[mid]
在左区,最小值在右区[mid+1,right]
中。 - 如果
nums[mid]<
最后一个元素,则nums[mid]
在右区,则最小值在[left,mid]
中。 - 如果
right=left
,则最小值为nums[left]
。
图解算法
Java代码
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
//二分查找重点是while(left <= right)
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] > nums[right]){
//最小值在右边区域
left = mid + 1;
}else if(nums[mid] < nums[right]){
//最小值在左边区域
right = mid;
}else{
return nums[left];
}
}
return -1;
}
}
三、小结
二分查找并不局限于有序数组,有某种策略来验证中间元素,并将查找范围缩小一半就可以用二分法。