题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路:
1. 数组中不包含重复元素,例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。那么我们可以采用二分搜索的改进版本实现。
2. 若数组的长度为0,则返回0。初始化三个指针left, right和mid,left指向数组的第一个元素,right指向数组的最后一个元素,mid初始化为0。因为数组是经过旋转的,此时旋转可能造成两种情况。第一种情况是:旋转位置为0,则相当于没有进行过旋转,且数组中不包含重复元素,若数组的长度为1,则会发生array[left] == array[right]的情况;另一种情况是:旋转的位置不为0,对于数组中没有重复的元素,则left指向左侧序列,right指向右侧序列,有array[left] > array[right]。
3. 若right - left = 1,此时right指向的就是旋转数组的最小元素,则返回array[right],结束循环。
4. 令mid = left + (right - left) / 2,则若array[mid] > array[left],则mid指向的元素左侧是有序的,旋转数组的最小值肯定在array[mid]的右侧,此时left = mid。
5. 若array[mid] < array[right],此时array[mid]的右侧是有序的,旋转数组的最小值肯定在array[mid]的左侧,此时right = mid;
6. 若数组没有被旋转,因为mid的初始值为0,直接返回第一个元素array[mid]。
7. 若数组中有重复元素,比如对数组{0, 1, 1, 1, 1, 1}进行旋转则会得到{1, 1, 0 ,1, 1}。令poi = 0,逐个遍历数组,寻找当array[i + 1] < array[i] 时的旋转数组最小值,若不存在这种情况,返回array[poi],即第一个元素。
public class Solution {
//若数组中包含重复元素,则进行逐个遍历
public int getPoi(int[] array){
int poi = 0;
if(array.length == 1){
return array[0];
}
for(int i = 0; i < array.length; i++){
if(array[i + 1] < array[i]){
poi = array[i + 1];
break;
}
}
return poi;
}
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int left = 0;
int right = array.length - 1;
int mid = 0;
/**若数组中没有重复的元素,left在左侧序列,right在右侧序列,
若数组反转位置%array.length != 0,则必有array[left] > array[right],左侧序列元素大于右侧序列元素
若数组中有重复元素,则可能会发生array[left] == array[right]。
**/
while(array[left] >= array[right]){
if(right - left == 1){
return array[right];
}
mid = left + (right - left)/2;
//array数组中有重复元素,逐个遍历
if(array[mid] == array[left] && array[mid] == array[right]){
getPoi(array);
}
//若array[mid] >= array[left],则mid的左侧是有序的,最小值在右侧;
//若array[mid] = array[left],可能有两种情况,1. mid = left 2.数组中有重复元素
if(array[mid] >= array[left]){
left = mid;
}
//mid的右侧是有序的,最小值在左侧
if(array[mid] <= array[right]){
right = mid;
}
}
//若数组是单调递增的,则返回第一个元素
return array[mid];
}
}