一、题目
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
要求:空间复杂度:O(1) ,时间复杂度:O(log n)
示例1:
输入:
[3,4,5,1,2]
返回值:
1
二、题解
2.1 数组遍历
此题最容易想到的办法是暴力法,即:通过对数组的遍历来获取最小值,算法流程:
1、先判断特殊情况,如果数组为空,则返回0;
2、创建最小值minNum
3、遍历数组每一个元素,将其和minNum进行比较,并更新最小值,minNum = min(minNum,num)
4、遍历结束返回minNum
时间复杂度O(N),空间复杂度O(1),这种方法不太推荐
2.2 二分法
此题中有一个重要的条件:非降序数组,那就是说该数组是有序的,即使在旋转之后也还是有一定的规律
一般来说排序数组查找问题首选二分法来解决,其时间复杂度可降为O(log n)
排序数组的查找问题首先考虑使用 二分法 解决,其可将 遍历法 的 线性级别 时间复杂度降低至 对数级别
算法流程:
1、初始化: 声明 i, j 双指针分别指向 array 数组左右两端
2、循环二分: 设 m = (i + j) / 2 为每次二分的中点( "/" 代表向下取整除法,因此恒有 i≤m1、当 array[m] > array[j] 时: m 一定在 左排序数组 中,即旋转点 x 一定在 [m + 1, j] 闭区间内,因此执行 i = m + 1
2、当 array[m] < array[j] 时: m 一定在 右排序数组 中,即旋转点 x 一定在[i, m]闭区间内,因此执行 j = m
3、当 array[m] = array[j] 时: 无法判断 mm 在哪个排序数组中,即无法判断旋转点 x 在 [i, m] 还是 [m + 1, j] 区间中。解决方案: 执行 j = j - 1 缩小判断范围
3、返回值: 当 i = j 时跳出二分循环,并返回 旋转点的值 array[i] 即可。
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
// 特殊情况判断
if (array.length== 0) {
return 0;
}
// 左右指针i j
int i = 0, j = array.length - 1;
// 循环
while (i < j) {
// 找到数组的中点 m
int m = (i + j) / 2;
// m在左排序数组中,旋转点在 [m+1, j] 中
if (array[m] > array[j]) i = m + 1;
// m 在右排序数组中,旋转点在 [i, m]中
else if (array[m] < array[j]) j = m;
// 缩小范围继续判断
else j--;
}
// 返回旋转点
return array[i];
}
}