题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4, 5, 1, 2}是数组{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
思路1:两个部分的指针
- 普通情况:
数组可以分为两个递增的部分,使用两个指针分别指向两个部分,
其中p1不断指向第一部分的最右,p2不断指向第二部分的最左。 - 特殊情况:
数组中有相同的值,如1,0,1,1,1
无法移动指针,对此情况只能O(n)便利。
代码:
#include<iostream>
using namespace std;
int RotationMin(int data[], int length) {
int p1 = 0;
int p2 = length - 1;
if (data[p1] < data[p2])
return data[p1];
int mid;
while (data[p1] >= data[p2])
{
if (p2 - p1 == 1)
return data[p2];
mid = ((p2 - p1) >> 1) + p1;
if (data[p1] == data[p2] && data[mid] == data[p1]) {
int minValue = data[p1];
for (int i = p1; i <= p2;i++) {
minValue = min(minValue, data[i]);
}
return minValue;
}
if (data[mid] >= data[p1]) {
p1 = mid;
}
else {
p2 = mid;
}
}
return data[mid];
}
int main()
{
int a[] = { 4,5,1,2,3};
cout << RotationMin(a, 5);
}
需要注意的是:p1 = mid;
,代表的是p1一直在第一部分的数组
如果是p1 = mid+1;
也可以使用下面的写法:
思路2:最小值困在两个指针之间
思路:mid的值比p1大说明最小值肯定在mid+1及其右边,因此可以+1
如果等于p1的值或者小于都有可能在包含mid 的区间内
同理,如果找的是最大值就可以在这个情况下mid-1
- 代码:
#include<iostream>
using namespace std;
int RotationMin(int data[], int length) {
int p1 = 0;
int p2 = length - 1;
if (data[p1] < data[p2])
return data[p1];
int mid = ((p2 - p1) >> 1) + p1;
while (p2-p1!=1)
{
if (data[p1] == data[p2] && data[mid] == data[p1]) {
int minValue = data[p1];
for (int i = p1; i <= p2;i++) {
minValue = min(minValue, data[i]);
}
return minValue;
}
if (data[mid] > data[p1]) {
p1 = mid+1;
}
else {
p2 = mid;
}
mid = ((p2 - p1) >> 1) + p1;
}
return min(data[p1],data[p2]);
}
int main()
{
int a[] = {3,4,0,1,2};
cout << RotationMin(a, 5);
}
由于只有两个元素时,mid总是第一个元素,因此直接返回两个的最小值即可