题目描述
一个递增排序的数组的一个旋转(把一个数组最开始的若干元素搬到数组的末尾,称之为数组的旋转),输出旋转数组的最小元素。
解题思路:
旋转之后的数组实际上可以划分成两个有序的子数组:前面子数组的大小都大于后面子数组中的元素
注意到实际上最小的元素就是两个子数组的分界线。本题目给出的数组一定程度上是排序的
,因此我们试着用二分查找法
寻找这个最小的元素。
(1)我们用两个指针left,right分别指向数组的第一个元素和最后一个元素
。按照题目的旋转的规则,第一个元素应该是大于最后一个元素的(没有重复的元素)。
但是如果不是旋转,第一个元素肯定小于最后一个元素。
(2)找到数组的中间元素。
中间元素大于第一个元素,则中间元素位于前面的递增子数组,此时最小元素位于中间元素的后面。我们可以让第一个指针left指向中间元素。
移动之后,第一个指针仍然位于前面的递增数组中。
中间元素小于第一个元素,则中间元素位于后面的递增子数组,此时最小元素位于中间元素的前面。我们可以让第二个指针right指向中间元素。
移动之后,第二个指针仍然位于后面的递增数组中。
这样可以缩小寻找的范围。
(3)按照以上思路,第一个指针left总是指向前面递增数组的元素,第二个指针right总是指向后面递增的数组元素。
特殊情况考虑:旋转0个元素、三个指针相等情况(10111, 11101)
// import java.util.ArrayList; public class Solution { public int minNumberInRotateArray(int [] array) { // 判断特殊情况 if (array==null||array.length==0) return 0; int firstIndex = 0; int lastIndex = array.length - 1; // 这里初始化mid为0的原因是,如果旋转0个元素那么最小值就是第一个元素 int midIndex = 0; // 如果旋转0个元素则直接跳出循环 while (array[firstIndex] >= array[lastIndex]){ if (firstIndex+1==lastIndex){ midIndex = lastIndex; break; } // 三指针相等时,只能顺序查找,这种情况非常容易漏,要非常细心 if (firstIndex==lastIndex && firstIndex==midIndex){ return MinInOrder(array, firstIndex, lastIndex); } midIndex = (firstIndex + lastIndex) / 2; if (array[firstIndex] <= array[midIndex]){ firstIndex = midIndex; } else{ lastIndex = midIndex; } } return array[midIndex]; } public int MinInOrder(int [] array, int low, int high){ int ret = array[low]; for (int i=low+1; i<high; i++){ if (array[i] < ret){ ret = array[i]; } } return ret; } }