剑指offer之面试题8:旋转数组的最小数字

来源:互联网 发布:mysql create trigger 编辑:程序博客网 时间:2024/06/05 16:05

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减序列的一个旋转,输出旋转数组的最小元素。例如数组{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));    }}
0 0