题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解题思路
第一反应是用暴力法,不过,这道题肯定不能如此简单。
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length ==0)
return 0;
int count = 0;
for(int i=0;i<array.length;i++){
if(array[i]>array[i+1])
{
count = array[i+1];
break;
}
}
return count;
}
}
大致用二分法解决
原数组是非递减,旋转后的数组中,由两部分非递减组成,第一部分非递减的值要高于第二部分非递减的值。
二分法需要中间值和目标值进行比较,目标值不存在的情况下,常使用端点值。那么,用左端点还是右端点呢?
有三种可能情况。
-
最小值在mid左侧。
如旋转数组为 [5,1,2,3,4]
此时array[mid] = 2,array[left] = 5,array[right]= 4
array[mid]<array[left],最小值在左侧[left,mid]
array[mid]<array[right],最小值一定不在右侧,即在[left, mid] -
最小值在mid右侧
如旋转数组为 [2,3,4,5,1]
此时array[mid] = 4,array[left] = 2,array[right] = 1
array[mid]>array[left],最小值无法确定是否在左侧
array[mid]>array[right],最小值一定在右侧,即在[left, mid]
因此,每次中间值array[mid]和右端点array[right] 进行比较
特殊情况
[1,1,1,1,1]、[1,0,1,1,1]、[1,1,1,0,1]
即array[mid]=array[right],此时无法确定最小值在何处,逐渐缩小右端范围,即right = right-1
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int left = 0;
int right = array.length -1;
int mid = 0;
if(array.length ==0)
return 0;
//二分查找
while(left<=right)
{
mid = (left+right)/2;
//中间值<右端值,最小值一定不在右侧,所以范围缩小至左端
if(array[mid]<array[right]){
right = mid;
}
//中间值>右端值,最小值肯定在右端
else if(array[mid]>array[right]){
left = mid+1;
}
//中间值 = 右端值,逐渐缩小范围
else
right = right-1;
}
return array[mid];
}
}