本系列博客为本人的刷题笔记,日后复习可以查看。
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
刷题平台:牛客网
题目解析
剑指offer中的分析,我们注意到旋转之后的数组实际上可以划分为两个排序的字数组,而且前面的字数组的元素大于或者等于后面字数组的元素。我们还注意到最小的元素刚好是这两个字数组的分界线。在排序的数组中可以用二分查找实现O(logn)的查找。本题给出的数组在一定程度上是排序的,因此我们可以试着用二分查找法的思路来寻找这个最小的元素。
- 1.把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
- 2.接着我们可以找到数组中间的元素。如果中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时最小元素应该位于该中间元素之后,然后我们把第一个指针指向该中间元素,移动之后第一个指针仍然位于前面的递增子数组中。
- 3.同样,如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时最小元素应该位于该中间元素之前,然后我们把第二个指针指向该中间元素,移动之后第二个指针仍然位于后面的递增子数组中。
- 4.第一个指针总是指向前面递增数组的元素,第二个指针总是指向后面递增数组的元素。最终它们会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素,这就是循环结束的条件。
示意图如下:
特殊情况:
- 如果把排序数组的0个元素搬到最后面,这仍然是旋转数组,我们的代码需要支持这种情况。如果发现数组中的一个数字小于最后一个数字,就可以直接返回第一个数字了。
- 下面这种情况,即第一个指针指向的数字、第二个指针指向的数字和中间的数字三者相等,我们无法判断中间的数字1是数以前面的递增子数组还是后面的递增子数组。正样的话,我们只能进行顺序查找。
如下图所示,{1,0,1,1,1}和{1,1,1,0,1}都是{0,1,1,1,1}的旋转数组。
代码实现
牛客网不好调试,在本地写好的代码,参考了牛客网的解析,具体代码如下。
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
int length = rotateArray.size();
if(length == 0){
return 0;
}//if
int p1 = 0,p2 = length - 1;
int mid = 0;
// rotateArray[p1] >= rotateArray[p2] 确保旋转
while(rotateArray[p1] >= rotateArray[p2]){
// 分界点
if(p2 - p1 == 1){
mid = p2;
break;
}//if
mid = p1 + (p2 - p1) / 2;
// rotateArray[p1] rotateArray[p2] rotateArray[mid]三者相等
// 无法确定中间元素是属于前面还是后面的递增子数组
// 只能顺序查找
if(rotateArray[p1] == rotateArray[p2] && rotateArray[p1] == rotateArray[mid]){
return MinOrder(rotateArray,p1,p2);
}//if
// 中间元素位于前面的递增子数组
// 此时最小元素位于中间元素的后面
if(rotateArray[mid] >= rotateArray[p1]){
p1 = mid;
}//if
// 中间元素位于后面的递增子数组
// 此时最小元素位于中间元素的前面
else if(rotateArray[mid] <= rotateArray[p2]){
p2 = mid;
}//else
}//while
return rotateArray[mid];
}
private:
// 顺序寻找最小值
int MinOrder(vector<int> &num,int left,int right){
int result = num[left];
for(int i = left + 1;i < right;++i){
if(num[i] < result){
result = num[i];
}//if
}//for
return result;
}
};
int main(){
Solution s;
vector<int> num1 ={0,1,2,3,4,5};
vector<int> num2 = {3,4,5,1,2};
vector<int> num3 = {1,0,1,1,1,1};
int res1 = s.minNumberInRotateArray(num1);
int res2 = s.minNumberInRotateArray(num2);
int res3 = s.minNumberInRotateArray(num3);
cout<<res1<<"\n"<<res2<<"\n"<<res3<<endl;
return 0;
}