题目(Java题解)

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

示例
input:
    [3,4,5,1,2]
output:    
    1
解题思路
首先明确题目后不难快速得出一个Brute Force的方法,一个O(N)的算法怎么看都不是很糟糕,但是面试官显然想看到的不是这么简单的方法,因此可以考虑通过二叉搜索法实现,现在考虑特殊情况递增数组的旋转,[3,4,5,6,7,8,9,1,2]。维护两个指针left=0,right=8。首先找到mid=4,nums[mid]=7 > nums[right],显然目标值不会在mid的左侧,因此left更新为mid,如果nums[mid]<nums[right],说明最小值在mid或者mid左边,此时更新right为mid,最后left和right相邻的时候,从left到right必然时非递增的。即此时right对应的值为目标值。
left=4,right=8,mid=6,nums[mid]=9
left=6,right=8,mid=7,nums[mid]=1
left=6,right=7,nums[left]>nums[right]
返回nums[right];
考虑一般情况,即为非递减数组,如果存在[1,1,1,1,1,2,1,1,1],此时mid为4,nums[mid]=1,不能判断属于左侧还是右侧,对于这种情况应该通过直接遍历的方式实现。
同理还是要询问面试官是否需要处理特殊情况。

时间复杂度:
基于比较的时间复杂度O(lgN),特殊情况的时间复杂度为O(N)

实例代码
Binary
public class Solution {
   public int minNumberInRotateArray(int [] array) {
       if(array == null || array.length == 0){
           return -1;
       }
       int left = 0;
       int right = array.length - 1;
       while(right - left != 1){
           int mid = left + (right - left) / 2;
           if(array[mid] == array[right]){
               return processWithBrute(array);
           }else if(array[mid] > array[right]){
               left = mid;
           }else{
               right = mid;
           }
       }
       return array[right];
   }
    public int processWithBrute(int[] array){
        int min = array[0];
        for(int i = 1; i < array.length; i++){
            if(array[i] < min){
                min = array[i];
            }
        }
        return min;
    }
}
测试用例
1. 功能性测试,一个升序排序数组的翻转
2. 边界值测试,只包含一个数字的数组
3. 特殊输入测试,输入为空