题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转,输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}是数组{1,2,3,4,5}的一个旋转,该数组的最小值为1。
题目分析:
我们可以通过旋转以后的数组中的元素的分布方式找出其中的一些规律:
数组{3,4,5,1,2}中,最左边的数字(3)大于最右边的数字(2),由于原数组是递增排序的,所以左边的数字(3,4,5)都比右边的数字(1,2)大,这样我们可以将该数组划分为两个序列分别是序列1{3,4,5}、序列2{1,2},那么我们就可以按照二分查找的方法查找最小数字1。
具体查找方法如下:
如:该数组为
int arr[5]={3,4,5,1,2};
第一步:用两个指针分别指向该数组的第一个元素和最后一个元素,即arr[0]arr[4];
第二步:查找数组的中间元素arr[mid];
第三步:用中间元素和数组的第一个元素分别和第一个元素和最后一个元素作比较,如果中间元素比第一个元素大,那么该中间元素一定是在第一个序列中的,这时,将第一个指针指向中间元素即arr[2];如果中间元素小与最后一个元素,那么中间元素一定是在第二个序列中的,这时将第二个指针指向中间元素。
第四步:重复上述步骤二,直到第一个指针指向第一个序列的最后一个元素,第二个指针指向第二个序列的第一个元素,即两个指针相邻,那么最小的元素就是第二个指针所指向的元素。
如图:
通过分析题目我们就可以很好的写出程序了,当然我们也要考虑到其他情况,当数组中元素为
{1,1,1,0,1}或{1,0,1,1,1}时,我们无法判断中间元素在第几个序列中,这是我们就要用另一种方法进行查找最小元素了。
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int Min(int *arr,int size)
{
assert(arr);
assert(size >=0);
int left = 0;
int right = size - 1;
int mid = left;
while (arr[left] >= arr[right])
{
if (right - left == 1)//若两指针相邻,则后一个指针所指的元素为最小值
{
mid = right;
break;
}
mid = (left + right) / 2;//求中间元素
if ((arr[left] == arr[right]) && (arr[mid] == arr[left]))
//若出现中间元素和左右两边的元素都相等时直接找最小元素,用下面的函数实现
return MinInOrder(arr,left,right);
if (arr[mid] >= arr[left])
{
left = mid;
}
else if (arr[mid] <= arr[right])
{
right = mid;
}
}
return arr[mid];
}
int MinInOrder(int *arr, int left, int right)
{
int i = 0;
int min = arr[left];
for (i = left + 1; i < right; i++)//直接遍历数组寻找最小的元素
{
if (arr[left]>arr[i])
{
min = arr[i];
break;
}
}
return min;
}