题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
实现思想
这里的实现方法有三种,三种都做简单的介绍,代码实现的是效率最高的一种方法。
第一种方法:第一种方法是最笨的一种方法,因为题目要求找该数组最小值,所以不管数组的排列方式,直接逐个查找就可以找到数组的最小值并返回。
第二种方法:第二种方法稍作改进,因为数组的排列方式是前面几个是按照递增顺序排列的大数,如题目中的3、4、5,后面紧接着就是这个数组的最小值,所以只需要按照顺序判断数组的数值比前一个小返回这个数即为数组的最小值。
第三种方法:第三种方法效率最高,但是实现起来也最麻烦,用到的办法是二分查找的办法。先用两个下标指向数组的最左端和最右端,然后二分查找如果左端指向的数的小于中间的,就将左端的指针指向中间,如果右端的指针大于中间,就将右端的指针指向中间,直到左端的指针和右端的指针相邻,就查找结束。
代码实现
#include <stdc++.h>
using namespace std;
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
int size = rotateArray.size();
int left = 0;
int right = size - 1;
int mid = -1;
if(size == 0) return 0;
//当左边的一直大于右边的,这是个必然条件
//如果一旦这个条件不成立则表示已经找到了
//其实跳出循环的条件只有break,所以下面的while(rotateArray[left] >= rotateArray[right])
//改成while(1)也是可以的,已经测试通过了
while(rotateArray[left] >= rotateArray[right]) {
if(left == right - 1) {
mid = right;
break;
}
mid = (right + left) / 2;
if(rotateArray[left] <= rotateArray[mid])
left = mid;
if(rotateArray[right] >= rotateArray[mid])
right = mid;
}
return rotateArray[mid];
}
};
int main()
{
int rotate[] = {3,4,5,1,2};
vector<int> rotateArray(rotate, rotate+5);
Solution S;
int minNumber = S.minNumberInRotateArray(rotateArray);
cout << minNumber << endl;
cout << "Hello world!" << endl;
return 0;
}
运行截图
输出数组中最小的:
总结
-
注意代码中的等号问题,因为数组中的数据可以为等号,在牛客网测试时,
while(rotateArray[left] >= rotateArray[right])
中的判断条件我缺少了等号,通过率只有30%多点。 -
int型的向量如果赋初值,可以先给数组赋初值,然后通过数组再初始化向量。具体的方式:
int rotate[] = {3,4,5,1,2}; vector<int> rotateArray(rotate, rotate+5);
-
关于本题还有一点需要强调:while循环的结束条件其实只有left == right -
1,也就是只有当左边的指针和右边的指针相邻时才结束while循环,大家可以将while(rotateArray[left] >= rotateArray[right])
改为while(1)
试试,代码依旧可以运行,并且所有测试用例也都可以通过,因为只有当两个指针相邻的时候才会找到此数组的最小值。