【剑指offer】2.4.2 查找和排序

面试题11:旋转数组的最小数字

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

解答:和二分查找一样,我们用两个指针分别指向数组的第一个元素和最后一个元素。接着找到数组中间的元素。如果该中间元素大于或者等于第一个指针指向的元素,说明此时数组中最小的元素应该位于该中间元素的后面,可以把第一个指针指向该中间元素,从而缩小查找范围。

    同样,如果中间元素小于或者等于第二个指针指向的元素,则说明此时数组中最小的元素应该位于该中间元素的前面,可以把第二个指针指向该中间元素,从而缩小查找范围。

    以此循环下去,最终第一个指针将指向前面子数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。

    还有一种特殊的情况,就是当两个指针指向的数字及它们中间的数字三者相同的时候,我们无法判断中间的数字是位于前面的子数组还是后面的子数组,也就无法移动两个指针来缩小查找的范围。此时不得不采用顺序查找的办法。实现代码如下:

int MidInOrder(vector<int> rotateArray)
{
	if(rotateArray.size() == 0)
	{
		throw new std::exception("Invalid parameters");
	}

	int len = rotateArray.size();
	int result = rotateArray[0];

	for(int i = 1;i < len;i++)
	{
		if(result > rotateArray[i])
		{
			result = rotateArray[i];
		}
	}

	return result;
}

int minNumberInRotateArray(vector<int> rotateArray) 
{
	if(rotateArray.size() == 0)
	{
		throw new std::exception("Invalid parameters");
	}

	int left = 0;
	int right = rotateArray.size() - 1;
	int mid = left;//初始化为第一个元素,若数组本身有序,可直接返回

	while(rotateArray[left] >= rotateArray[right])//若用left<right作为判断条件则会陷入死循环
	{
		if(right - left == 1)
		{
			mid = right;
			break;
		}
		
		mid = ((right - left) >> 1) + left;
                //若三数相等只能遍历
		if(rotateArray[left] == rotateArray[mid] 
		&& rotateArray[mid] == rotateArray[right])
		{
			return MidInOrder(rotateArray);
		}
		if(rotateArray[mid] >= rotateArray[left])
		{
			left = mid;
		}
		else
		{
			right = mid;
		}
	}

	return rotateArray[mid];
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章