《剑指offer》:[11]旋转数组的最小数字

  题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小的元素。
  例如:数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.
  本题目是直接给的旋转的数组:那么数组如何旋转呢?其实也很简单:
  首先确保给数组排序,最好的时间复杂度O(NLogN)。
(1)如果元素的个数是奇数:最中间的元素不动,i和j都指向中间元素的下标。然后i++和j--,同时交换;停止的条件是i<0;
(2)如果元素的个数是偶数:i=n/2-1;j=n/2;i--;j++;停止的条件是i<0;
然后回到正题,求翻转数组的最小数字:
方案一:循环遍历法。此法比较笨,一般这样的方法就不要说了,一般的都能想到。时间复杂度是O(N)。
方案二:二分查找法。
以上面的题目为例:{3,4,5,1,2};
交换以后,被切成两个递增的序列。我们可以发现第一个元素是大于或等于第二个元素的(当然还有特例:如果把前面的0个元素搬到后面,第一元素小于最后的一个元素)。

先看常规的方法:采用二分查找,不断的缩小范围,当最大和最小相邻的时候停止。具体示意如下图一:


图一

注意两种特殊情况:
(1)移动了0个元素,也就是还是原先的序列;

(2)对于如下数组,当第一个指针和第二个指针以及中间元素都相等时,我们无法判断增减序列,进而进行缩小范围。此时我们必须采用顺序查找;

第二种情况如下图二:


图二

具体代码实现如下:

#include<iostream>
using namespace std;
int FindOrder(int *array,int length);
int FindMin(int *array,int length);
int arr1[5]={3,4,5,1,2};
int arr2[5]={1,0,1,1,1};
int FindMin(int *array,int length)
{
	if(NULL==array || length <=0)
		throw "INVALID INPUT!";
	int index1=0;
	int index2=length-1;
	int MidInde=index1;//十分必要,因为这个事避免上述说的注意1时的特殊情况;
	while(array[index1]>=array[index2])
	{
		if(1==index2-index1)
			return array[index2]; 
		MidInde=(index1+index2)/2;
		if(array[index1]==array[index2] && array[index2]==array[MidInde])//特殊情况(2);
			return FindOrder(array,length);//顺序查找;
		if(array[MidInde]>=array[index1])
			index1=MidInde;
		if(array[MidInde]<=array[index2])
			index2=MidInde;
	}
	return array[index1];
}

int FindOrder(int *array,int length)
{
	int min=array[0];
	for(int i=0;i<length;i++)
	{
		if(min>array[i])
		{
			min=array[i];
		}
	}
	return min;
}
int main()
{
	cout<<"In arr1,the min is :"<<FindMin(arr1,5)<<endl;
	cout<<"In arr2,the min is :"<<FindMin(arr2,5)<<endl;
	system("pause");
	return 0;
}
运行结果:







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值