发现还是数组这种最简单的编码才适合我,遇到树,链表这些真的是一头雾水,自己也不知道怎么实现。言归正传,该篇文章介绍如何求旋转数组的最小值,求最大值可以适当改编即可。
什么是旋转数组呢,就是将一个数组的前几个元素和后面几个元素互换位置。例如原数组(升序的数组)为{0,1,2,3,4,5,6,7,8,9},将其旋转后变为{5,6,7,8,9,0,1,2,3,4}。如何求该数组的最小值呢,有一种方法是直接按顺序比较,但是这就体现不出旋转数组的特性了,所以更好的解法应该是采用二分法来求得该数组的最小值。我们可以发现在旋转数组中9坐标的数都比它小,右边的数也都比它小。我们设有2个指针,左指针指向最左边的元素,右指针指向最右边的元素。我们判断中间的元素和最左边元素的大小,如果中间的数大于左指针指向的元素,证明最小的数字在中间数字的右边。这样我们就可以缩小范围啦。
代码如下
#include<iostream>
#include<cstdlib>
#include <stack>
#include <stdio.h>
#include<time.h>
using namespace std;
int Min(int a[], int length)
{
if (a == nullptr || length <= 1) //如果出现数组中只有一个元素的就直接报错吧
throw new exception("Invalid parameters");
int left = 0;
int right = length - 1;
while (a[left] > a[right])
{
if (right <= left+2) //数组中有2个或者三个元素,最右边的元素都是最小的
return a[right];
int mid = (left + right) / 2;
if (a[mid] >= a[left])
left = mid;
else if (a[mid] < a[right])
right = mid;
}
return a[right];
}
int main()
{
int a[] = { 44,45,46,1,2,3,15,33,41 };
int min=Min(a, 6);
cout << min << endl;
system("pause");
}
不过很显然这种方法不是很完善的,因为没有考虑一种比较特殊的情况,就是数组中拥有重复元素的时候。比如数组{1,1,1,0,1},{1,0,1,1,1}。这种时候就只能选择顺序查找的办法啦。
改进代码如下:
#include<iostream>
#include<cstdlib>
#include <stack>
#include <stdio.h>
#include<time.h>
using namespace std;
int MinInOder(int a[], int left,int right)
{
int result = a[left];
for (int i = left+1; i < right; i++)
{
if (a[i] < result)
result = a[i];
}
return result;
}
int Min(int a[], int length)
{
if (a == nullptr || length <= 1)
throw new exception("Invalid parameters");
int left = 0;
int right = length - 1;
while (a[left] >=a[right])
{
if (right <= left+2)
return a[right];
int mid = (left + right) / 2;
if (a[right] == a[left]
&& a[mid] == a[right])
return MinInOder(a, left,right);
if (a[mid] >= a[left])
left = mid;
else if (a[mid] <= a[right])
right = mid;
}
return a[right];
}
int main()
{
int a[] = { 1,1,1,1,0,1,1,1,1 };
int min=Min(a, 6);
cout << min << endl;
system("pause");
}