题目链接
牛客在线oj题——旋转数组的最小数字
题目描述
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1≤n≤10000,数组中任意元素的值:0≤val≤10000
要求:空间复杂度:O(1) ,时间复杂度:O(logn)
题目示例
示例1
输入:
[3,4,5,1,2]
返回值:
1
示例2
输入:
[3,100,200,3]
返回值:
3
解题思路
根据题目中给出的旋转定义,数组被切割成两个非递减的序列,而序列的连接处就是最小值的地方。因此可以得出当arr[i] > arr[i + 1]的时候,arr[i + 1]就是那个最小值
还有一种更加高效的方法:使用二分查找进行定位
根据旋转的定义可以不仅可以得出数组前半部分和后半部分都是非递减的序列,并且数组的前半部分一定比后半部分大
我们按照二分查找的思想,分别定义left , right , mid
如果left小于等于mid,说明left和mid位于同一个非递减序列,而right位于另一个非递减序列,因此最小值一定在right所在的非递减序列,因此这时应该让left = mid
而如果left大于mid,说明right和mid位于同一个非递减序列,而left位于另一个非递减序列,因此最小值一定在left所在的非递减序列或mid所在位置,因此这时应该让right = mid
还需要注意一点,题目中说的是非递减序列,因此可能出现多个相等的数字,这时如果left和right和mid都相等,说明最小值就在left和right这个序列之间,只能通过遍历进行搜索
完整代码
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int left = 0;
int right = array.length - 1;
int mid = 0;
while(array[left] >= array[right]){
if(right - left == 1){
mid = right;
break;
}
mid = left + ((right - left) >> 1);
if(array[left] == array[right] && array[left] == array[mid]){
int result = array[left];
for(int i = left + 1; i < right; i++){
if(array[i] < result){
result = array[i];
}
}
return result;
}
if(array[mid] >= array[left]){
//结果应该在右半部分
left = mid;
} else {
right = mid;
}
}
return array[mid];
}
}