旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,咱们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的全部元素都大于0,若数组大小为0,请返回0.算法

发现用二分法解决这个问题很好,{3,4,5,1,2}能够分红两个排好序的子数组{3,4,5}{1,2},而左边的每一个数必定大于右边的每一个数,因此能够声明两个索引left=0,right=length-1,mid=left(为啥这么设置初始值请看代码注释).
开始循环,循环条件为list[left] >= list[right]。咱们要作的事情就是让left一直处于第一个数组里且不断接近第一个数组尾,让right一直处于数组二且不断接近数组二的头。让mid等于(left+right)/2,当mid大于left时,说明此时mid还在第一个数组里,这时就让left=mid;继续循环mid再等于(left+right)/2,假设此时mid小于left了,那么它必定处于第二个数组里了,并且它也小于right(由于right时第二个数组当前最大的).当left+1==right的时候就能够跳出循环了,由于此时right就是咱们要找的元素。数组

public class Jianzhi{

    public static void main (String[] args){
        int[] num = {3,4,5,1,2};
        int m = find(num ) ;
        System.out.println(m);
    }
    public static int find(int[] list) {
        if(list == null){  //数组为null时
            return -1 ;
        }
        if(list.length == 0 ){  //数组长度为0则返回0
            return 0 ;
        }
        int left = 0 ;    
        int right = list.length - 1 ;
        int mid = left ;    //注意:这一步让mid等于left是有用意的,若是list是排好序的,
                            //那么直接返回list[mid] 
        while(list[left] >= list[right]){ 
            if(left + 1 == right){
                    return right ;
            }
            mid = (left + right) / 2 ;
            if(list[mid] == list[left] && list[mid] == list[right]){
                return minInOrder(list,left,right);
            }
            if(list[mid] >= list[left]){
                left = mid ;
            }
            if(list[mid] <= list[right] ){
                right = mid  ;
            }
        }
        return list[mid] ;
    }
public static int minInOrder(int[] list , int left , int right ){
    int result = list[left] ;
    for(int i = left+1 ; i < right ; i++){
        if(result > list[i] ){
            result = list[i] ;
        }
    }
    return result ;
}

}

可能你们比较疑惑为何有如下这句:spa

if(list[mid] == list[left] && list[mid] == list[right]){
                return minInOrder(list,left,right);
            }

考虑下面这种状况
图片描述code

此时 第一个和第二个索引以及mid索引指向的指都是1,三个数字相同。但咱们不能区分出最小的数字在mid的左边仍是右边,就无法进行判断了。此时,就不得不采用顺序查找方法:排序

public static int minInOrder(int[] list , int left , int right ){
        int result = list[left] ;
        for(int i = left+1 ; i < right ; i++){
            if(result > list[i] ){
                result = list[i] ;
            }
        }
        return result ;
    }

整个算法最重要的仍是让left和right都往两个数组的公共边界靠拢。索引

完毕。图片

相关文章
相关标签/搜索