首页 > 代码库 > 【剑指offer】旋转数组的最小数字

【剑指offer】旋转数组的最小数字

题目描述:

    

       把一个数组最开始的若干个元素搬到数组的末尾,称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。


分析描述:


       求一个数组中的最小值,最简单的办法就是逐个比较数组中各个元素的值,遍历完整个数组,即可得数组中最小元素。但这种方法存在的问题是时间复杂度为O(n)。

       利用题目中给出的条件:递增排序数组的旋转。利用递增排序的特点,可以用二分查找方法实现时间复杂度为O(logn)的查找。步骤就是设置两个位置标记,分别指向数组中的第一个元素和最后一个元素,然后比较中间元素与第一个和最后一个的大小。如果中间元素比第一个元素大,说明中间元素位于第一个递增排序数组中,此时将位置标记的第一个标记指向中间坐标。如果中间元素比最后一个元素小,说明中间元素位于第二个递增排序的数组中,此时将位置标记的第二个标记指向中间坐标。依次类推,直到第一个标记与第二个标记紧挨着时,第二个标记指向的元素就是数组中的最小值。

       上面的分析是建立在第一个元素一定大于等于最后一个元素的基础上的,因为题目描述的是若干个元素,因此,如果没有搬动元素,那么第一个元素小于最后一个元素。此时只需要将第一个元素返回即可。

       分析貌似完成了,但对于特殊的情况有遗漏,如{1,0,1,1,1}和{1,1,1,0,1},此时第一个元素、中间元素、最后元素三者相等。此时必须从头开始遍历整个数组逐个比较了。


int MinInOrder(int *array, int length) /*第一个元素、最后一个元素与中间元素三者相等时,遍历整个数组*/
{
	int count;
	int tmp = array[0];

	for(count = 1; count < length; count++)
	{
		if(tmp > array[count])	
			tmp = array[count];
	}

	return tmp;
}

int
Min(int *array, int length)
{
	if(array == NULL || length <= 0){    /*检查所给参数是否正确*/
		printf("Invalid parameters.\n");	
		return -1;
	}

	int Index1, Index2, Indexmid;
	Index1 = 0; Index2 = length - 1;
	if(array[Index1] < array[Index2]) /*如果整个数组就是递增的,则直接返回第一个元素*/
		return array[Index1];

	while(array[Index1] >= array[Index2]){

		if(Index2 - Index1 == 1){
			Indexmid = Index2;	
			break;
		}

		Indexmid = (Index1 + Index2) / 2;	

		if(array[Index1] == array[Index2] && 
				array[Index1] == array[Indexmid])
		return MinInOrder(array, length);

		if(array[Index1] <= array[Indexmid])
			Index1 = Indexmid;	
		else if(array[Index2 >= array[Index2]])
			Index2 = Indexmid;
	}

	return array[Indexmid];
}