旋转数组的最小数字10

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

解题思路:题目的意思是在一个部分有序的数组中查找最小数字。
1. 利用输入的旋转数组特性,旋转之后的数组可分为两个有序的子数组。
2. 因为旋转是把最开始的若干元素搬到数组的末尾,因为输入数组是递增的,所以前面子数组的元素都 >= 后面子数组元素。
3. 用两个指针分别指向数组的第一个元素和最后一个元素,按照旋转规则,排除特例(特例是把排序数组的前面的0个元素搬到后面),第一个元素应该大于或者等于最后一个元素。
4. 找到数组中间的元素,中间元素是重点!
5. 如果中间元素位于前面的递增数组,那么它应该大于或者等于第一个指针指向的元素,此时数组中最小的元素应该位于中间元素的后面。我们可以把第一个指针指向该中间元素,缩小查找范围。
6. 如果中间元素位于后面的递增数组,那么它应该小于或者等于第二个指针指向的元素,此时数组中最小元素应该位于中间元素的前面。我们可以把第二个指针指向该中间元素,缩小查找范围。
7. 不管是移动第一个指针还是第二个指针,查找范围都会缩小到原来的一半。
8. 再用更新之后的指针重新一轮查找。
9. 当这两个指针相邻时,第二个指针指向的就是最小元素。即循环结束条件(point2 - point1 == 1)。
10. 返回中间下标值即为要查找的数字。
特殊情况:当两个指针指向的数字及它们的中间的数字三者相同的时候,我们无法判断中间的数字是位于前面的子数组还是后面的子数组。如:{0, 1, 1, 1, 1}的两个旋转->{1, 1, 1, 1, 0}和{1, 1, 1, 0, 1}。此时也就无法移动两个指针来缩小范围。判断有这种情况,我们不得不用顺序查找
测试用例:

int main(){
    //输入递增数组{1, 2, 3, 4, 5, 6}的一个旋转
    int arr[6] = {3, 4, 5, 6, 1, 2};
    //int arr[5] = {1, 1, 1, 0, 1};  //传入长度改为5, Output: 0
    //保存最小数字
    int min;
    //查找其中的最小数字, 并返回结果
    min = searchMin(arr, 6);
    //输出结果
    std::cout << "Minimum number is: " << min;  //Output: 1.    

    return 0;
}

searchMin函数实现:

//考虑到有可能输入旋转数组是这样:{1, 0, 1, 1, 1}或{1, 1, 1, 0, 1},此时两个指针和中间数字的值都相同,只能采用
//顺序查找的方法
int minInOrder(int *arr, int index1, int index2){
    int result = arr[index1]; //初始化为数组的第一个值
    for(auto i = index1 + 1; i <= index2; ++i){
        if(arr[i] < result)
            result = arr[i];
    }
    return result;
}

//主体函数实现
int searchMin(int *arr, int length){
    if(arr == NULL || length <= 0)
        throw new std::exception("Invalid parameters!");
    //两个指针(下标)
    int index1 = 0, index2 = length - 1;
    //中间下标,也是结果的下标
    int indexMid = index1;  //此处需要赋值其index1, 这样下面的循环不成立便会直接返回。
    while(arr[index1] >= arr[index2]){  //由于是递增的旋转数组,前面子序列的值必然大于后子序列的值
        if(index2 - index1 == 1){
            indexMid = index2;//如果下标相邻,最小值就在index2
            break;
        }

        //确定中间值
        indexMid = (index1 + index2) / 2;

        //作一判断,若三个下标相等,则只能采取顺序查找
        if(arr[index1] == arr[index2] && arr[index1] == arr[indexMid])
            return minInOrder(arr, index1, index2);

        if(arr[indexMid] >= arr[index1]) //如果中间值大于前面的值,则代表中间值在前子序列,必然不是最小元素,则
            index1 = indexMid;  //令重新赋值index1跳到中间值, 缩小查找范围。
        else if(arr[indexMid] <= arr[index2]) //如果中间值小于后面的值,则代表中间值在后子序列,有可能是最小元素,但
            index2 = indexMid;  //若不能达到退出循环的条件,必须继续缩小范围进行查找
    }
    return arr[indexMid];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值