《剑指offer》面试题11:旋转数组的最小数字

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。


例如,数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。


分析:
我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面子数组的元素都大于或者等于后面子数组的元素。和二分查找法一样,我们用两个指针分别指向数组的第一个元素和最后一个元素。按照这种思路,第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最终第一个指针将指向前面数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。这就是循环结束的条件。

注意:考虑特殊情况(见代码)

java参考代码如下:

package chapter2;

public class P82_MinNumberInRotatedArray {
    //在旋转数组中查找target,找到返回下标,未找到返回-1.
    public static int searchinrotatedarray(int[] data,int target){
        int left=0,right=data.length-1;
        while (left<=right){
            int mid=left+(right-left)/2;
            if(data[mid]==target) return mid;
            else if(data[mid]<data[right]){//右边部分有序
                if(data[mid]<target&&target<=data[right])
                    left=mid+1;
                else
                    right=mid-1;
            }else if(data[mid]>data[right]){//左边部分有序
                if(data[left]<=target&&target<data[mid])
                    right=mid-1;
                else
                    left=mid+1;
            }else//有重复值的情况
                --right;
        }
        return -1;
    }
//找到旋转数组的最小值
    public static int findMin(int[] data){
        int left=0,right=data.length-1;
        while (left<right){
            int mid=left+(right-left)/2;
            if(data[mid]<data[right])
                right=mid;
            else if(data[mid]>data[right]){
                left=mid+1;
            }else if(data[mid]==data[right]){
                --right;
            }
        }
        return data[left];
    }

    public static void main(String[] args){
        int[] data={2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2};
        int[] data1={1,1,3,1,1,1,1};
        int target=3;
        System.out.println(searchinrotatedarray(data,target));
        System.out.println(findMin(data));
        System.out.println(findMin(data1));
    }
}

参考处(博客评论):http://www.cnblogs.com/grandyang/p/4040438.html

代码实现如下:

int Min(int *numbers,int length)
{
	if(numbers==nullptr || length<=0)
		throw new std::exception("Invalid parameters.");

	int index1=0;
	int index2=length-1;
	int indexMid=index1;//考虑到如果是旋转0个元素,即原数组的情况。
	while(numbers[index1]>=numbers[index2])
	{
		if(index2-index1==1)
			break;
		indexMid=(index1+index2)/2;

		//如果下标index1、index2和indexMid指向的三个数字相等,
		//则只能顺序查找
		if(numbers[index1]==numbers[index2] && numbers[indexMid]==numbers[index1])
			return MinInOrder(numbers,index1,index2); 

		if(numbers[indexMid]>=numbers[index1])
			index1=indexMid;
		else if(numbers[indexMid]<=numbers[index2])
			index2=indexMid;
	}

	return numbers[indexMid];
}

int MinInOrder(int* numbers,int index1,int index2)
{
	int result=numbers[index1];

	for(int index=index1;index<=index2;++index)
	{
		if(result>numbers[index])
			result=numbers[index];
	}

	return result;
}

测试用例:
a.功能测试(输入的数组是升序排序数组的一个旋转,数组中有重复数字或者没有重复数字)。
b.边界值测试(输入的数组是一个升序排序的数组,只包含一个数字的数组)。
c.特殊输入测试(输入nullptr指针)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值