问题描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解决思想
最简单的方法就是遍历法,但是对于这种已经局部排序完成的数组有些浪费了。
我们可以研究下其性质。以[3, 4, 5, 1, 2]这个数组为例,我们可以发现其由两个有序的子数组组成,即[3, 4, 5]和[1, 2]。最显著的特点是最小的元素1位于两个有序的子数组交界处。我们利用二分法来解决这个问题。
如上图所示,我们设定指针r和l分别指向数组的第一个元素和最后一个元素。既然我们使用二分法,我们就考虑设定中间指针m=(l + r) / 2。如上图所示,第一次设定m,我们可以得到Array[m] = 5,我们通过比较发现5 >= 3,而且我们假定前面的子数组中所有元素>=后面的子数组中的所有元素,好,我们就抛弃了5之前所有的元素,为啥抛弃呢?因为他们都不是最小的。好,我们令l = m,我们就到了图中的第三步。我们再次计算m = (l + r) / 2,得到了Array[m] = 1,我们发现1 <= 2,也就是1肯定位于后面的那个子数组中,那么1后面的我们都不看了,抛弃1后面的所有元素,我们令r = m。如此循环下去,直到我们发现l = r - 1,也就是这俩指针相邻了。此时得到了我们的最小值Array[r]。
每次搜索范围都减小一半,充分地利用了”旋转数组“的性质,时间复杂度O(logn)。
我的代码
class Solution {
public:
// 形参是vector容器,这里参考了牛客网考试的形式
int minNumberInRotateArray(vector<int> a){
int size = a.size();
// 根据题目要求,若数组长度为0,返回0
if(size