题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减序列的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
分析:
最直观的思路是直接从头到尾遍历数组,查找最小的元素,时间复杂度为
O(n)
。没有利用旋转数组已经分为了两个排序子序列的特性,还不够高效。
推荐解法:
旋转数组实际上可以划分为两个排序的子数组,前面的子数组都大于或者等于后面子数组的而元素,最小元素刚好是两个子数组的分界线。因此可以用二分查找的思想实现时间复杂度为
O(n)
的查找。
牛客AC代码:
import java.util.ArrayList;
public class Solution {
public static int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int begin = 0;
int end = array.length-1;
while(array[begin]>=array[end]){
// 普通查找
if(end - begin<=1)
return normalFind(array,begin,end);
int mid = (begin+end)/2;
// 当begin/end/mid位置上的元素相等时,无法判断最小元素位于左边还是右边
// eg: [1, 0, 1, 1, ] 和 [1, 1, 1, 0, 1]都是[0, 1, 1, 1, 1]的旋转数组
// 第一种情况最小值0在mid的左边,第二种情况最小值0在mid的右边
// 只能进行普通查找
if((array[mid] == array[begin]) && (array[mid] == array[end])){
return normalFind(array,begin,end);
}
if(array[mid]>=array[begin]){//去右边查找
begin = mid;
}else if(array[mid]<=array[end]){//去左边找
end = mid;
}
}
return array[begin]; // 只能返回begin的值
}
// 正常的循环遍历查找
public static int normalFind(int[] array,int begin,int end){
if(begin == end){
return array[begin];
}
int min = array[begin];
for(int i=begin+1;i<=end;i++){
if(array[i]<min){
min = array[i];
}
}
return min;
}
参考
1. 何海涛,剑指offer名企面试官精讲典型编程题(纪念版),电子工业出版社