题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减序列的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
乍一看,觉得这个挺简单的。直接遍历就好,直接遍历的时间复杂度也只有O(n)。但后来想想还是还是用二分写一下吧,毕竟不是考试什么的,有时间的话还是尝试着效率更好的方法。
用pre和next分别指向开头和结尾的元素,用mid指向中间的元素
1.如果array[mid]小于array[next],即mid指向的元素还是在最小数字后面半段。把next指向mid
2.如果array[mid]大于array[pre],即mid指向的元素在最小数字前面的半段数组,所以把pre指向mid。
3.重新计算mid
当pre和next相邻时结束,输出后面的array[next]。
当我这样写完了之后发现,当数组直接以最小数字开头时是不正确的,例如{1,2,3,4}
所以改成了输出array[pre]和array[next]较小的一个。
然后由发现了新的问题:当数组为{1,1,1,0,1,1,1,1,1}这样时,用二分的方法没有办法判断,mid到底是属于前半段还是后半段,所以在这种情况下我任然使用了遍历。
代码如下:
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if( array == null || array.length == 0 ) return 0;
if( array.length == 1 ) return array[0];
int pre = 0;
int next = array.length-1;
int mid = (pre + next)/2;
while(pre < next){
//{1,0,1,1,1,1,1,1,1}||{1,1,1,1,1,1,0,1,1,1}
if( array[pre] == array[mid] && array[pre]== array[next]){
int min = array[0];
for(int i =1;i<array.length;i++){
if( array[i] < min ) min = array[i];
}
return min;
}
//二分
if( pre == next -1) {
return (array[pre]>array[next])?array[next]:array[pre];
}
if( array[pre] >= array[next]){
if( array[mid] >= array[pre]){
pre = mid;
mid = (pre + next)/2;
}else if( array[mid] <= array[next] ){
next = mid;
mid = (pre + next)>>1;
}
}else{
return array[pre];
}
}
return array[next];
}
}