题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组
{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
最简单的方法就是直接扫描一遍数组,找到数组中最小的数字,这样做它的时间复杂度是#card=math&code=O%28n%29&height=20&width=36)

观察到最小值在第一部分和第二部分的分界处,且在第二部分,另外可以观察到,由于第二部分是数组的前半部分搬到末尾的,所以第二部分中的值是小于等于第一部分中的值。
对于顺序查找问题,我们可以使用二分查找法。我们使用两个指针分别指向第一部分的开头和第二部分的结尾,然后将这两个值与数组中间的值进行比较,如果中间的值比第一部分的开头大,说明中间的值还在第一部分,我们将第一部分的开头指针移动到中间;同理,如果中间值比第二部分末尾的值小,则中间的值还在第二部分,则将第二部分末尾的指针移动到中间。以此类推,直到两个指针相差一个距离,则到了分界处,取第二部分指针所对应的值,该值即为最小值。图示如下:
但是上面的方法却又一个特例,即中间值与两个指针所指的值相等时,则无法知道如何移动指针
上面两个数组都是 {0, 1, 1, 1, 1} 的旋转,并且中间的值与两个指针指向的值相同,但是中间值一个在第一部分,一个在第二部分,所以我们这时是无法知道如何移动指针,碰到这种情况,我们只能顺序查找了,代码如下
public class Min {public static int min(int[] arr) {int start = 0;int end = arr.length - 1;int mid = 0;// 如果 start 的值小于 end,说明数组没有进行旋转,则返回数组的第一个值,这就是 mid = 0 的原因while (arr[start] >= arr[end]) {// 如果两个指针相差 1 个距离,则返回第二个指针指向的值if (end - start == 1) {mid = end;break;}mid = (start + end) / 2;// 如何中间的值和两个指针的值相等,则进行顺序查找if (arr[start] == arr[end] && arr[start] == arr[mid]) {return minInOrder(arr, start, end);}// 如果中间的值比 start 的值大,则将 start 移至中间if (arr[mid] >= arr[start]) {start = mid;} else if (arr[mid] < arr[end]) {// 否则中间的值比 end 小,则将 end 移至中间end = mid;}}return arr[mid];}// 顺序查找的代码public static int minInOrder(int[] arr, int start, int end) {int minResult = arr[start];for (int i = start; i <= end; i++) {if (minResult > arr[i]) {minResult = arr[i];}}return minResult;}public static void main(String[] args) {int[] arr = {3, 4, 5, 1, 2};System.out.println(min(arr)); // 1}}
