题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序(非递减数组)的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
方法一:直接遍历查找最小的元素,时间复杂度为O(n)
public int minNumberInRotateArray(int[] arr){
int min = arr[0];
for(int i=0; i < arr.length; i++){
if(arr[i] < min){
min = arr[i];
}
}
return min;
}
方法二:利用二分查找提高效率,时间复杂度为O(log n)
思路:首先定义两个指针 p1、p2 分别指向数组的第一个元素和最后一个元素,同时还有一个指针mid指向数组的中间,由旋转数组的特点可知,最小数字把整个数组分为两部分,mid可能位于前半部分也可能位于后半部分,通过比较 array[p1] 和 array[mid] 、或者 array[p2] 和 array[mid] 来缩小查找的范围,从而提升效率。
特殊情况:
1. 未旋转的数组其实也是一个特殊的旋转数组,它的最小数字是数组的第一个元素。
2. 有可能数组的第一个元素等于中间元素等于最后一个元素,这个时候就无法确定这个中间元素是位于旋转数组的前半部分还是后半部分了,这个时候只能用顺序查找。
测试用例:
1. 功能测试:输入一个递增数组的旋转(包含重复数字和不包含重复数字)。
2. 边界测试:输入只有一个元素的数组。
3. 负面测试:输入空指针。
public class test_eleven {
public int minNumberInRotateArray(int[] array){
if(array == null || array.length == 0)return 0;
int p1 = 0;
int p2 = array.length-1;
int min = array[0]; //未旋转的时候,数组的最小数字为第一个元素
int mid = 0;
while(array[p1] >= array[p2]){ //表示数组旋转了
if(p2-p1 == 1){ //当两个指针的距离为1
min = array[p2];
break;
}
mid = (p1+p2)/2;
if(array[p1] == array[mid] && array[mid] == array[p2]){ //这个特殊情况只能用顺序查找
min = findMin(array, p1, p2);
}
if(array[p1] <= array[mid]){ //一般情况用二分查找,效率较高
mid = p1;
}
else if(array[mid] <= array[p2]){
mid = p2;
}
}
return min;
}
private int findMin(int[] array, int p1, int p2) { //定义一个顺序查找函数
int min = array[0];
for(int i=1;i<array.length;i++){
if(array[i] > min) min = array[i];
}
return min;
}
}