[剑指Offer] 旋转数组的最小数字
问题描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0
分析
思路一
记录当前元素cur的前一个元素pre,当cur < pre的时候,cur就是最小的元素,时间复杂度为\(O(n)\)
int minNumberInRotateArray(vector<int> rotateArray) {
int len = rotateArray.size();
if (len == 0) return 0;
int pre = rotateArray[0];
for(int i = 0; i < len; ++i) {
if (rotateArray[i] < pre) {
return rotateArray[i];
}
pre = rotateArray[i];
}
}
思路二
借鉴二分查找的思想,数组旋转后被分为两部分
low 指向 左部分, high指向右部分
左右部分的分界点就是最小值
通过不断地缩小[low, high]的范围,最终low指向左部分最后一个元素,high指向右部分第一个元素,也就是最小值
这样做能在牛客AC但其实是错的,无法通过{1, 0, 1, 1, 1}的检验
int minNumberInRotateArray(vector<int> rotateArray) {
if (rotateArray.size() == 0) return 0;
int low = 0, high = rotateArray.size() - 1;
int mid = 0;
// 数组有序时直接返回首元素
if (rotateArray[0] < rotateArray[high]) {
return rotateArray[0];
}
while (low < high-1) {
mid = (low + high) / 2;
if (rotateArray[mid] > rotateArray[low]) {
low = mid;
} else if (rotateArray[mid] < rotateArray[high]){
high = mid;
} else {
++low;
}
}
return rotateArray[high];
}
这道题的坑很多,牛客网上的测试用例不够完善,这里自己增加了一些特殊的测试用例,参考(chao xi)了大佬的代码才通过了所有的测试用例
{1, 1, 1, 1, 1}
{1, 0, 1, 1, 1}
{3, 4, 5, 1, 2} // 普通
{1, 2, 3, 4, 5} // 旋转0
这种做法的low并不会固定在数组的左部分,由于rotateArray[mid] > rotateArray[low]
时的处理是low = mid + 1
,low有可能会到数组的右部分第一个元素,这时对数组[low, high]部分的有序判断将返回数组的min
#include <iostream>
#include <vector>
using namespace std;
int minNumberInRotateArray(vector<int> rotateArray)
{
if (rotateArray.size() == 0) return 0;
int low = 0, high = rotateArray.size() - 1;
int mid = 0;
while (low < high) {
// 数组有序时直接返回首元素,low可能指到右部分的第一个元素(也就是min)
if (rotateArray[low] < rotateArray[high]) {
return rotateArray[low];
}
mid = (low + high) / 2;
if (rotateArray[mid] > rotateArray[low]) {
low = mid + 1; // 配合上面rotateArray[low] < rotateArray[high]的判断,能处理{1, 0, 1, 1, 1}
} else if (rotateArray[mid] < rotateArray[high]){
high = mid;
} else {
++low;
}
}
return rotateArray[low];
}
int main()
{
int a1[] = {1, 1, 1, 1, 1};
int a2[] = {1, 0, 1, 1, 1};
int a3[] = {3, 4, 5, 1, 2}; // 普通
int a4[] = {1, 2, 3, 4, 5}; // 旋转0
vector<int> input1(a1, a1+5);
vector<int> input2(a2, a2+5);
vector<int> input3(a3, a3+5);
vector<int> input4(a4, a4+5);
cout << minNumberInRotateArray(input1) << " expected: 1" << endl;
cout << minNumberInRotateArray(input2) << " expected: 0" << endl;
cout << minNumberInRotateArray(input3) << " expected: 1" << endl;
cout << minNumberInRotateArray(input4) << " expected: 1" << endl;
}