{3,4,5,1,2} {2,2,4,1,2} {1,0,1,1,1}还不足以包括所有情况,不同的处理方式有更多细节需要注意,因此需要进行不同的分析。

思路1:最直观的比较是arr[i]和arr[i+1]比(每次比较相邻的数),然后i++,只要arr[i]比arr[i+1]大,就可以找到最小元素。否则就是全部相等的情况,直接返回最后一个值就行(任意一个值),这样的时间复杂度是O(n)。

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length == 0){
            return 0;
        }      
        int i = 0;
        while(i<array.length-2 && array[i] <= array[i+1]){
              i++;
        }
        return array[i+1];
    }
}

思路2 进行优化,将时间复杂度从O(n)降低,这时就想到二分查找,复杂度可以降低到O(logn)。
如果二分的部分:
1.arr[left] > arr[mid] 显然结果是在左半边,需要进行比较处理,while去比较。而arr[left] < arr[mid] 说明结果在右半边,因此重新设定数组的首尾索引
2.arr[mid] > arr[right]是在右半边,继续比较处理,利用while比较。arr[mid] < arr[right] 在左半边,因此重新设定数组的首尾索引
3.值得注意的是,{2,2,2,2}、{2,2,2,2,4,1,2}以及{1,0,1,1,1}这种情况,是相等的情况。在二分搜索的情况下,无法判断最小值是在左边还是右边,因此时间复杂度退化成O(n),就只能使用思路1的方法才能比,或者其他O(n)的算法,二分分不出结果,需要进行处理。
  这里给出大佬的2种处理方式,第一种:在二分后处理,比较时如果相等,就将数组缩减,比如{1,0,1}就缩减成{0,1}再进行判断。如果全相等的话,时间复杂度仍是O(n),{1,0,1,1,1}的复杂度则介于O(n)和O(logn)之间了,算是一种优化。

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
         int i = 0, j = array.length - 1;
         while (i < j) {
             if (array[i] < array[j]) {
                return array[i];
             }
             int mid = (i + j)/2;
             if (array[mid] > array[i]) {//结果在右边。  {1,0,1,1,1}判断不出来留到最后
                 i = mid + 1;
              } else if (array[mid] < array[j]) { //结果一定在左边
                j = mid; // 
              } else i++;  //这是相等的情况,i++后,重新二分,进行判断
            }
        return array[i];
    }
}

//边界的确定将会在第二种处理方式时分析

第二种处理,在二分前处理。如果首尾相等了,就先缩减数组,这个处理是首尾同时缩减。可以将所有的重复元素都减去,顺利将{2,3,4,1,2}变成{3,4,1}这种类型,而全相等的也可以处理。运行n/2次得到结果。当{2,2,2,2,3,1,2}和{4,5,6,4,4,4,4}的缩减后的情况,将会具体分析

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
     if (array.length == 0) 
         return 0;
        int i = 0, j = array.length - 1;
        while(array[i] == array[j]){
            i++;
            j--;
        }     
        while(array[i] > array[j]){
            int mid = i + (j-i) / 2; //大佬的写法很细致
            if(array[mid] >= array[i]){ //{2,2,2,3,1}这种情况是出现相等的情况
                i = mid + 1;    //因此结果在右边,让i变成右边数组的一个元素
            }else if(array[mid] <= array[j]){  //{5,6,4,4,4}是二分后右边相等的情况
                j = mid;    //说明结果在左边,注意边界,4是最小,所以应该赋值mid的角标
            }
        } 
        return array[i];
    }
}
//这里解释为什么一个加1一个不处理成减1,不加1是由于mid边界可能是最小的(给出了示例)
//而加1是由于原边界mid的右边,要么等于mid,要么大于mid。而最小值还在右边,不在左边。
//由于整个数组全相等的情况已经排除,说明右边的最小值一定小于边界值mid,所有可以放心加1