现在的位置: 首页 > 综合 > 正文

每日一题(27) – 旋转数组的最小数字

2013年10月14日 ⁄ 综合 ⁄ 共 2056字 ⁄ 字号 评论关闭

题目来自剑指offer

题目:


思路:

根据指针low,mid,high三个指针指向元素的大小确定二分往左走还是往右走

如果arr[low] <= arr[mid]:则区间[low,mid]的元素是递增的,有升有降应该在右边区间,应该往右走

如果arr[low] > arr[mid]:  则区间[low,mid]的元素是有递增有递减,则应该往左走

终止条件:

区间只剩两个元素时,终止。此时该区间肯定值一个大一个小(high指向),此时返回high指向元素即可

注意:

有一种情况解决不了。

在arr[low] = arr[mid] = arr[high]时,此时无法确定之后处理左区间还是右区间。此时只能对该区间直接顺序遍历找到最小数

举例:

当数组元素为 1 0 1 1 1 和 1 1 1 0 1,上述思路无法同时处理这两种情况。

即上述思路,要求low,mid,high三个指针指向的三个元素至少有一个元素是不同的。

代码:

不完全正确的代码:

int BinSearch(int nArr[],int nStart,int nEnd)
{
	assert(nArr != NULL && nStart >= 0 && nEnd >= nStart);
	int nLow = nStart;
	int nHigh = nEnd;
	int nMid = -1;
	while (nLow + 1 < nHigh)
	{
		nMid = (nLow + nHigh)/2;
		if (nArr[nLow] <= nArr[nMid])//向右走
		{
			nLow = nMid;
		}
		else //向右走
		{
			nHigh = nMid;
		}
	}
	//终止时,有指针nLow和nHigh相邻,指向的两个元素肯定是一升一降,nLow指向大元素,nHigh指向小元素
	assert(nHigh >= nStart && nHigh <= nEnd);
	return nArr[nHigh];
}

正确代码:

int BinSearch(int nArr[],int nStart,int nEnd)
{
	assert(nArr != NULL && nStart >= 0 && nEnd >= nStart);
	int nLow = nStart;
	int nHigh = nEnd;
	int nMid = -1;
	while (nLow + 1 < nHigh)
	{
		nMid = (nLow + nHigh)/2;
		if (nArr[nLow] == nArr[nMid] && nArr[nMid] == nArr[nHigh])
		{
			//不能区分往左走还是往右走,此时要顺序查找
			int nMin = 0x3f3f3f3f;
			for (int i = nLow;i <= nHigh;i++)
			{
				if (nMin > nArr[i])
				{
					nMin = nArr[i];
				}
			}
			return nMin;
		}
		if (nArr[nLow] <= nArr[nMid])//向右走
		{
			nLow = nMid;
		}
		else //向右走
		{
			nHigh = nMid;
		}
	}
	//终止时,有指针nLow和nHigh相邻,指向的两个元素肯定是一升一降,nLow指向大元素,nHigh指向小元素
	assert(nHigh >= nStart && nHigh <= nEnd);
	return nArr[nHigh];
}

测试代码:

#include <iostream>
#include <assert.h>
using namespace std;

int BinSearch(int nArr[],int nStart,int nEnd)
{
	assert(nArr != NULL && nStart >= 0 && nEnd >= nStart);
	int nLow = nStart;
	int nHigh = nEnd;
	int nMid = -1;
	while (nLow + 1 < nHigh)
	{
		nMid = (nLow + nHigh)/2;
		if (nArr[nLow] == nArr[nMid] && nArr[nMid] == nArr[nHigh])
		{
			//不能区分往左走还是往右走,此时要顺序查找
			int nMin = 0x3f3f3f3f;
			for (int i = nLow;i <= nHigh;i++)
			{
				if (nMin > nArr[i])
				{
					nMin = nArr[i];
				}
			}
			return nMin;
		}
		if (nArr[nLow] <= nArr[nMid])//向右走
		{
			nLow = nMid;
		}
		else //向右走
		{
			nHigh = nMid;
		}
	}
	//终止时,有指针nLow和nHigh相邻,指向的两个元素肯定是一升一降,nLow指向大元素,nHigh指向小元素
	assert(nHigh >= nStart && nHigh <= nEnd);
	return nArr[nHigh];
}

int main()
{
	//int nArr[5] = {3,4,5,1,2};
	//int nArr[5] = {3,1,2,3,4};
	//int nArr[5] = {3,1,1,1,1};
	//int nArr[5] = {3,3,3,3,1};
	//int nArr[5] = {1,1,1,1,1};
	//int nArr[5] = {1,0,1,1,1};
	int nArr[5] = {1,1,1,0,1};
	cout<<BinSearch(nArr,0,4)<<endl;
	system("pause");
	return 1;
}

抱歉!评论已关闭.