旋转数组的最小数字

问题描述:

把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的旋转

输出旋转数组的最小元素。例如{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;
}

posted @ 2014-12-01 13:02  阿木木在发呆  阅读(159)  评论(0编辑  收藏  举报