思路一
遍历。复杂度为O(n)
/**
* @Auther: Mason
* @Date: 2020/07/22/9:04
* @Description:
*/
public class Solution {
public int minArray(int[] numbers) {
int len = numbers.length;
if (len == 1) return numbers[0];
// 如果第一个数小于最后一个数,肯定第一个数是最小的。
// 比如:1.......5 ,说明此数组没有进行旋转。否则 之前的数组,5将在1前面。不可能。
// 相等不能判定,比如:5,1,2,5
if (numbers[0] < numbers[len - 1]) return numbers[0];
int i = 1;
// 找到第一个 减小 的数字。
// 3,4,5,1,2 ----->为1
// 3,3,3,1,2 ----->为1
// 4,4,4,4,4 ----->超出范围,为4
while (i < len && numbers[i] >= numbers[i - 1]) {
i++;
}
if (i > len - 1) return numbers[len - 1];
return numbers[i];
}
}
思路二
最好的方法,利用二分查找,但是也要考虑特殊情况。
/**
* @Auther: Mason
* @Date: 2020/07/22
* @Description:
*/
/*
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
*/
public class Solution {
public int minArray(int[] numbers) {
// [1.....5] 肯定第一个是最小的。
if (numbers[0] < numbers[numbers.length - 1]) return numbers[0];
// [5......5]
// [5,5,5,1,5,5,5] 也可能是 [5,5,5,5,5]
if (numbers[0] == numbers[numbers.length - 1]) return searchInOrder(numbers);
// [5.........3]
// 数组有两段,我要找到,第二段的第一个数字。
int left = 0;
int right = numbers.length - 1;
int middle;
while (left < right - 1) {
middle = (left + right) / 2;
if (numbers[middle] >= numbers[left]) {
left = middle;
} else {
right = middle;
}
}
return numbers[right];
}
// [10,1,10,10,10] 主要是为了应对这样的情况。
public int searchInOrder(int[] arr) {
for (int i = 1; i < arr.length; i++) {
if (arr[i] < arr[i - 1]) return arr[i];
}
return arr[0]; // [1,1,1,1,1] 这样的情况。
}
}