题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减序列的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
思路:直接从头到尾遍历数组一次,即可
public int minNumberInRotateArray(int [] array) {
if(array==null||array.length<=0)
return 0;
int min=0;
for(int i=1;i<array.length;i++){
if(array[i]<array[min]){
min=i;
}
}
return array[min];
}
但这样的话就没有利用输入的数组本身的特性,时间效率为O(n),还可以更优吗?达不到面试官的肯定
数组旋转以后,分为两个排序的子数组,既然是排序的,可以用二分查找的思想吗?
答案是可以的,分析一下,旋转之后,前面的子数组的元素都大于或等于后面的子数组元素,最小的元素恰好是两个数组的分界线。用两个指针分别指向数组的第一个元素和最后一个元素。第一个元素大于或等于最后一个元素(不完全对,后面会讨论)
取中间的元素,与两个指针指向的元素分别比较,如果大于或等于前面指针指向的元素,则说明中间的元素位于前面的子数组,最小的元素位于中间元素后面,可以将第一个指针指向该中间元素,从而缩小范围,此时第一个指针仍然指向前面的子数组;如果小于或等于后面指针指向的元素,则位于后面的子数组,此时最小元素应位于该元素前面,将第二个指针指向该元素,此时第二个指针仍然指向后面的子数组。
递归,最终第一个指针指向的是前面子数组的最后一个元素,第二个指针指向的是后面子数组的第一个元素(也是最小元素)。结束。
基于以上思路,可以写出如下代码:
public static int minNumberInRotateArray(int [] array) {
if(array==null||array.length<=0)
return 0;
int index1=0;
int index2=array.length-1;
int indexMiddle=index1;
while(array[index1]>=array[index2]){
//定义出口
if(index2-index1==1){
indexMiddle=index2;
break;
}
indexMiddle=(index1+index2)/2;
if(array[index1]<=array[indexMiddle]){
index1=indexMiddle;
}
else if(array[index2]>=array[indexMiddle]){
index2=indexMiddle;
}
}
return array[indexMiddle];
}
依据旋转数组的定义:把前面若干个元素移到后面,所以前面的元素总是大于或等于后面的元素,但是有个例外:0个元素移到后面,此时最小的元素就是第一个元素,所以可以让minIndex初始化为index1。
如果出现下面这种情况呢?
{0,1,1,1,1}旋转成{1,1,1,0,1}或{1,0,1,1,1},第一种情况中间元素1位于前面的子数组,第二种情况中间元素1位于后面的子数组,不能确定到底位于前面还是后面,此时只能顺序查找。
故完整代码如下,已在牛客网提交成功:
import java.util.ArrayList;
public class Solution{
public static int minNumberInRotateArray(int [] array) {
if(array==null||array.length<=0)
return 0;
int index1=0;
int index2=array.length-1;
int indexMiddle=index1;
while(array[index1]>=array[index2]){
//定义出口
if(index2-index1==1){
indexMiddle=index2;
break;
}
indexMiddle=(index1+index2)/2;
//{0,1,1,1,1}旋转成{1,1,1,0,1}或{1,0,1,1,1},只能顺序查找
if(array[index1]==array[index2]&&array[index1]==array[indexMiddle]){
return MinInorder(array,index1,index2);
}
if(array[index1]<=array[indexMiddle]){
index1=indexMiddle;
}
else if(array[index2]>=array[indexMiddle]){
index2=indexMiddle;
}
}
return array[indexMiddle];
}
public static int MinInorder(int[] array,int index1,int index2){
int result=array[index1];
for(int i=index1+1;i<=index2;i++){
if(array[i]<result){
result=array[i];
}
}
return result;
}
public static void main(String[] args){
int[] array={3,4,5,1,2};
System.out.println(minNumberInRotateArray(array));
}
}