题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
-
示例 1:
输入:[3,4,5,1,2]
输出:1 -
示例 2:
输入:[2,2,2,0,1]
输出:0
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
如果数组的第0个元素小于最后一个元素,说明旋转的位置为开头或结尾(和没旋转效果一样),最小元素就是第0个元素
这道题当然可以线性遍历,如果某个元素的值小于前一个元素的值,那么这个值就是最小值
不过这道题也可以用二分法,分三种情况:
- 如果number[mid] > number[right],那么left = mid + 1
- 如果number[mid] < number[right],那么right = mid(为什么不-1?因为当前number[mid]可能就是最小值)
- 如果number[mid] = number[right],无法说明最小值在mid的左侧还是右侧,但是可以说明一定不是number[right],可以right = right - 1
中途也可以提前终止循环,在mid > 0的前提下,若number[mid] < number[mid-1],可以直接返回number[mid]
代码详解
class Solution {
public int minArray(int[] numbers) {
int len = numbers.length;
// 特殊情况
if(len == 1 || numbers[len-1] > numbers[0]) {
return numbers[0];
}
// 二分法
int p = 0;
int q = len-1;
while(p < q) {
int mid = (q - p) / 2 + p;
// 提前终止循环的条件
if(mid > 0 && numbers[mid] < numbers[mid-1]) {
return numbers[mid];
}
// 更新左右指针
if(numbers[mid] > numbers[q]) {
p = mid + 1;
} else if(numbers[mid] < numbers[q]) {
q = mid;
} else {
--q;
}
}
return numbers[q];
}
}
注意点
- 那个提前终止循环的条件可以在运气好的时候减少时间消耗,但是也由于每次都判断,在大多数时候反而增加时间消耗,做题就无所谓了