1. 本题知识点
二分查找
2. 题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如:
原数组:{1,2,3,4,5}
输入旋转数组:{3,4,5,1,2}
输出旋转数组的最小元素:1
NOTE:给出的所有元素都大于 0,若数组大小为 0,请返回 0。
3. 解题思路
基本思路
-
将旋转数组对半分,可以得到一个非递减排序的数组,以及一个包含最小元素的新旋转数组。
-
将旋转数组再次对半分,又可以得到一个非递减排序的数组,以及一个包含最小元素的新旋转数组。此时,新旋转数组只剩两个元素,最后一个元素即最小元素。
新的旋转数组的数组元素是原数组的一半,从而将问题规模减少了一半,这种折半性质的算法的时间复杂度为 O(logN)。
代码实现思路
上面基本的思路已经有了,但还有一个关键问题,我们怎么知道对半分后,哪个数组是旋转数组,哪个数组是非递减排序的数组?
-
首先用两个指针 low 和 high 分别指向数组的第一个元素和最后一个元素,然后可以找到中间元素 mid。
-
此时 mid 指向的元素有两种情况:
-
该元素大于等于 low 指向元素,说明最小元素在 mid 后面的数组(包括 mid 指向的元素),于是将 low=mid。
-
该元素小于等于 high 指向元素,说明最小元素在 mid 前面的数组(包括 mid 指向的元素),于是将 high=mid。
-
-
当 low+1=high 时,此时 high 指向的就是最小元素。
4. 代码
public class Solution {
public int minNumberInRotateArray(int[] array) {
// 若数组大小为 0,返回 0。
if (array.length == 0) {
return 0;
}
int low = 0;
int high = array.length - 1;
int mid;
while (true) {
// 当 low+1=high 时,此时 high 指向的就是最小元素。
if (low + 1 == high) {
return array[high];
}
// 折半
mid = (low + high) / 2;
// mid 指向元素大于等于 low 指向元素,说明最小元素在 mid 后面的数组(包括 mid 指向的元素),于是将 low=mid。
if (array[mid] >= array[low]) {
low = mid;
}
// mid 指向元素小于等于 high 指向元素,说明最小元素在 mid 前面的数组(包括 mid 指向的元素),于是将 high=mid。
if (array[mid] <= array[high]) {
high = mid;
}
}
}
}