题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
思路及解答
import java.util.Scanner;
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String[] strings = bf.readLine().split(" ");
int[] arr = new int[strings.length];
for (int i = 0; i < arr.length; i++) {
arr[i] = Integer.parseInt(strings[i]);
}
int res = solution(arr);
System.out.print(res);
bf.close();
}
/*
* 思路:
* 1.我们注意到旋转之后的数组实际上可以划分为两个排序的子数组
* 2.而且前边的子数组大于或者后边的子数组
* 3.我们还注意到最小的元素刚好是这两个子数组的分界线
* 4.因为数组的部分排序的,所有我们利用二分查找法来找到数组中的最小元素
* 5.接着我们可以找到数组中间的元素
* 6.如果数组中间的元素位于前面的递增子数组,那么它应该大于或等于第一个指针指向的元素,此时
* 数组中的最小元素位于该中间元素的后边
* 7.如果数组中间的元素位于后面的递增子数组,那么它应该小于或等于第二个指针指向的元素,此时
* 数组中的最小元素位于该中间元素的前边
* 8.第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素
* 9.最终,第一个指针指前面子数组的最后一个元素,而第二个指针指向后面子数组的第一个元素
* 10.也就是说,它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小元素
*
* 11.如果排序数组前面0个,也就是说如果数组是完全有序的,那么直接返回第一个元素
*
* 12.出现了l和r指向的元素相同并且中间的元素也相同的情况【1 0 1 1 1】
*
* */
public static int solution(int[] arr){
if(arr == null || arr.length == 0) return 0;
int l = 0;
int r = arr.length - 1;
int min = l;
while(arr[l] >= arr[r]){
int mid = (l + r) >> 1;
if(r - l == 1){
min = r;
break;
}
//如果下标为 l、r 和 m 指向的数字相等,则只能顺序查找
if(arr[l] == arr[r] && arr[mid] == arr[r]){
return minInOrder(arr, 0, arr.length-1);
}
if(arr[mid] >= arr[l]){
l = mid;
}else if(arr[mid] <= arr[r]){
r = mid;
}
}
return arr[min];
}
public static int minInOrder(int[] arr, int l, int r){
int res = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i] < res){
res = arr[i];
}
}
return res;
}
}