这道题已经是写第三或第四次了,还是没办法一看到题目就有思路,这里根据题解加上个人的理解,总结一下这道题的思路。
题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
思路:
大佬说过:“排序数组的查找问题首先考虑使用二分法解决,其可将遍历法的线性级别时间复杂度降低至对数级别。”
确定使用二分法后,接下来的问题是如何缩小最小值所在范围。
设定中间位置为mid,右边界位置为las,左边界位置为fir
- numbers[mid]<numbers[las] 说明最小值不在mid~las位置之间,因为原来数组是升序排列,旋转了之后,除了最大值突降到最小值之间那一段,其它位置还是升序排列,如果最小值在这个范围内,应该不断升序,也就是说,最小值右边的数会始终小于最小值左边的数与实际矛盾,因此最小值应该在这个范围之前,即缩小范围让las=mid;
- numbers[mid]>numbers[las] 说明最小值在mid~las位置之间,原因同上,缩小范围让fir=mid+1
- numbers[mid]=numbers[las] 无法判断最小值所在范围,但为了缩小范围,让las-=1
- 最终缩小到fir==las时即是最小值的位置
class Solution {
public int minArray(int[] numbers) {
if(numbers.length==1) return numbers[0];
int fir=0,las=numbers.length-1;
while(fir<las){
int mid=fir+(las-fir)/2;
if(numbers[mid]<numbers[las]){
las=mid;
}else if(numbers[mid]>numbers[las]){
fir=mid+1;
}else las-=1;
}
return numbers[fir];
}
}