数组二:旋转数组的最小数字

/**
 * 题目:旋转数组的最小数字
 * 描述:   把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
 *  输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
 *  例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
 *  NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
 *解决方案:方法一:遍历数组,进行比较, 时间复杂度O(n)
 *    方法二:直接遍历数组,直到第一个后置位的数比前值位的数小的位置即可,时间复杂度O(n)
 *    优化解:二分查找思想,找到中间值与最左边的数值进行比较,如果比left大,说明他在left的递增区间内,将left赋值为min,
 *         同理与右边的数值进行比较,如果比右边小说明在right的递减区间内,将right赋值为mid;直到剩下的两个元素,此时一定为right-left=1;
 *         且right位置的值为旋转数组的最小值
 *旋转数组的特点:
 *  1.旋转之后的数组可以分为两个排序的子数组,且前面的子数组的元素都大于等于后面子数组的元素
 *  2.最小或者最大的元素位于两个子数组的分界
 *解题思路:利用左右指针和中间指针元素的大小关系判断中间元素位于前面的子数组还是后面的子数组,缩小查找范围
 *   需要考虑的特例:
 *  1.排序数组本身仍是该数组的一个旋转,
 *  2.如果数组里面有重复元素,那么有可能出现左右两指针元素和中间元素相同,无法判断中间元素属于前面子数组还是后面的子数组,此时用顺序查找
 *  
 * */

public class Two {

    public static int finMid(int[] arry) {
        if(arry.length == 0) {
            throw new RuntimeException("Empty");
        }
        int indexLow = 0;
        int indexHigh = arry.length-1;
        int indexMid = indexLow;
        
        while( arry[indexLow] >= arry[indexHigh]) {    
            if(indexHigh - indexLow ==1) {
                indexMid = indexHigh;
                break;
            }
            indexMid = (indexLow+indexHigh)/2;
            //考虑特例情况
            if(arry[indexMid] ==arry[indexLow] && arry[indexLow] == arry[indexHigh]) {
                return findMinInOrder(arry,indexLow,indexHigh);
            }
            if(arry[indexMid] >arry[indexLow] ) {
                indexLow = indexMid;
            }else {
                indexHigh = indexMid;
            }
        }
        return arry[indexMid];
    }
    /**
     * 顺序查找  直到第一个后置位的数比前值位的数小的位置即可
     * */
    private static int findMinInOrder(int[] arry, int indexLow, int indexHigh) {
            int result = arry[indexLow];
            for(int i = indexLow+1;i<indexHigh;i++) {
                if(result > arry[i]) {
                    return arry[i];
                }
            }
        return result;
    }
}

 

posted @ 2018-11-16 14:52  弄潮儿儿  阅读(146)  评论(0编辑  收藏  举报