把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
根据题目的描述,不难发现整个大数组可以分为两个子数组,前面一个子数组递增,后面一个子数组也是递增,而且最小的值刚好是两个子数组的分界线,每个子数组是增长排序的。第二个子数组的数小于等于第一个子数组的数(除了旋转0个数,也就是不移动数到后面去,这种情况下,数组还是原来的排序)
不难想到可以采用二分查找的思路来查找最小数,设置三个指针,一个指向头(head),一个指向尾(rear),还有一个指向中间(mid)。
如果mid的值大于等于head的值,那么这个mid的位置属于前子数组
如果mid的值小于等于rear的值,那么这个mid的位置数与后子数组
还有一种情况就是,mid的值、head的值、rear的值相等的时候,就无法判断出mid的位置是属于哪个子数组,所以这时候就需要直接遍历查询最小值
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
//设置两个指针,一个指向前面,一个指向末尾
int head = 0;
int rear = array.length - 1;
//设置中间指针,如果旋转0个数,那么数组就是直接有序的,不会进入循环,直接返回array[mid]
int mid = head;
while(array[head] >= array[rear]){
//结束条件,头尾相邻
if(rear - head == 1){
mid = rear;
break;
}
mid = (rear + head) / 2;
//三个节点的值都相等,无法判断mid属于哪个子数组,就按照顺序查找找到最小值
if(array[head] == array[rear] && array[head] == array[mid]){
return findInOrder(array,head,rear);
}
//中间节点大于head,那么中间节点属于前面递增的子数组
if(array[mid] >= array[head]){
head = mid;
}
//中间节点小于rear,那么中间节点属于后面的递增子数组
else if(array[mid] <= array[rear]){
rear = mid;
}
}
return array[mid];
}
private int findInOrder(int[] array,int head,int rear){
int result = array[head];
for(int i = head + 1;i <= rear;i++){
if(result > array[i]){
result = array[i];
}
}
return result;
}
//test
public static void main(String[] args){
int[] array = {1,2,3,1,1,1};
System.out.println(minNumberInRotateArray(array));
System.out.println(minNumberInRotateArray1(array));
}
}