剑指offer-----旋转数组里的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路一:顺序查找
如果数组旋转后,数组可分为两部分,前部分数字是非递减,后面元素也是非递减,从第二个元素开始判断,如果后一个元素(B)比前一个元素(A)小,那么后一个元素(B)则是旋转数组里最小元素。那么这样时间复杂度就是0(n)。代码如下:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if (rotateArray.size() == 0)
		return 0;
	int i = 0;
	while (i < rotateArray.size()-1)
	{
		//如果前一个数字比后一个大,那么后一个数字肯定是最小元素
		//如果前一个数字小于等于后一个数字,那么最小数字可能是该数字或者后面数字
		//等于情况   3 4  4   5   1  
		if (rotateArray[i] <= rotateArray[i + 1])
			i++;
		else   // 3  4  5  1  直接返回[2+1]
			return rotateArray[i+1];
	}
	//  3 3 3 3 3   循环出来后,i=4,可以返回[4],也可以返回[3],但是返回[3]空间复杂度小
	return rotateArray[i-1];   
    }
};

思路二:二分查找
由于数组分成的两部分都是有顺序的,并且是查找最小数字,可以选择用二分查找。
首先left=0,right=size()-1,因为旋转后,左边元素大于等于右边元素,左边第一个元素大于等于右边元素,即如果[mid]>=[left],那么说明最小元素在mid右边,那么left=mid;如果[mid]<[left],说明最小元素在mid左边,那么right=mid。那么left一直指向左边元素,right一直指向右边元素,当right-left=1时,即他们指向相邻的元素,right指向元素刚好是最小元素,就跳出循环。但是这种方法只能解决没有重复数字,但是如果是下面情况,二分查找将不适用:
在这里插入图片描述
代码如下:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
			int len = rotateArray.size();
			if (len == 0)
				return 0;
			int left = 0;
			int right = len - 1;
			int mid = 0;

			while (rotateArray[left] >= rotateArray[right])
			{
				mid = left + (right - left) / 2;
				if (right - left == 1)
				{
					mid = right;
					break;
				}
				if (rotateArray[left] == rotateArray[mid] && rotateArray[mid] == rotateArray[right])
				{
					//顺序排序
					int i = left;
					while (i<right)
					{
						if (rotateArray[i] <= rotateArray[i + 1])
							i++;
						else
							return rotateArray[i + 1];
					}
					return  rotateArray[i];
				}
				else {  //二分查找
					if (rotateArray[left] <= rotateArray[mid])
						left = mid;  //最小元素在mid右边,需要是left=mid,不能是mid+1,因为mid可能是最小元素
					else  
                     // 如  3 4 5 1  2  ,当left=2,right=4,mid=3,[mid]是最小元素,所以需要是right=mid,而不是right=mid+1
						right = mid;
				}
			}
			return rotateArray[mid];
		}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值