问题描述:
把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的旋转
输出旋转数组的最小元素。例如{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为一。
思路解析:
最简单的莫过于从头到尾遍历一遍找出最小元素,这种方法时间复杂度为O(n),但是没有使用旋转数组的
特性,肯定不符合面试官的要求。在排序数组中我们利用二分查找发实现O(logn)的查找。我们可以选用两
个指针,一个指向开始,一个指向结尾,按照旋转的原则第一个数应该是大于等于最后一个数的(有可能
旋转了0个元素,这时候就得做判断了,第一个元素即为所求)。若中间的数大于等于第一个指针指向的元
素此时数组中的最小元素应该位于中间元素的后面,我们就可以把第一个元素指向该中间元素缩小范围了。
同样,若中间元素元素位于后面的递增子数组,那么它就应该小于等于第二个指针指向的元素,我们可以把
第二个指针指向中间元素缩小查找范围。
上述思路即第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。
最终第一个指针将指向前面子数组的最后一个元素,第二个指针指向后面子数组的第一个元素,也是
最终它们会指向相邻的元素。第二个指针就是指向的最小元素。这就是循环结束条件。不过如果第一个
和最后一个元素相等时就得用普通查找了,此时已不符合上述规律。
参考代码:
int Min(int array[],int length)
{
if (array == NULL || length <= 0)
{
//return -1;
throw new exception("Invalid parameters");
}
int index1 = 0;
int index2 = length-1;
int indexMid = index1;//考虑到了旋转0个的情况
while (array[index1] >= array[index2])
{
if (index2 - index1 == 1)
{
indexMid = indexMid;
break;
}
indexMid = (index1+index2)/2;
//第一个数,最后一个数,还有中间一个数相等的情况。例如数列:1 1 1 0 1
if (array[index1] == array[index2] && array[index1] == array[indexMid])
{
return MinInorder(array,index1,index2);
}
if (array[indexMid] > array[index1])
{
index1 = indexMid;
}
else
{
if (array[indexMid] <= array[index2])
{
index2 = indexMid;
}
}
}
return array[index2];
}
int MinInorder(int *array,int index1,int index2)
{
int result = array[index1];
for (int i = index1+1;i < index2;i++)
{
if (result > array[i])
{
result = array[i];
}
}
return result;
}