8. 旋转数组的最小数字

题目描述

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


解析

1. 递增数组的旋转,例如,数组{1 2 3 4 5},经过旋转可以是{2 3 4 5 1},{3 4 5 1 2},{1 2 3 4 5},{5 1 2 3 4},{4 5 1 2 3}。
2. 特例!这其中的数字可以重复,数组{0 1 1 1 1}可以旋转为{1 0 1 1 1},{1 1 1 0 1}等等。
3. 在可以可以缩小数组大小的时候,采用二分法查找。当遇到无法进行二分法缩小范围的时候,改用顺序查找法。

主要代码实现

int Min(int* number, int length){
    if(number == NULL || length <= 0){
        printf("输入有误!");
        return -1;
    }
    int startIndex = 0;
    int endIndex = length-1;
    int midIndex = startIndex;
    while(number[startIndex] >= number[endIndex]){
        // 如果startIndex和endIndex指向相邻的两个数,
        // 则startIndex指向第一个递增子数组的最后一个数字,
        // endIndex指向第二个子数组的第一个数字,也就是数组中的最小数字
        if(endIndex - startIndex == 1){
            midIndex = endIndex;
            break;
        }
        midIndex = (startIndex + endIndex) / 2;

        //数组的收尾元素、中间元素大小相等,无法决定使用二分法
        if(number[startIndex] == number[endIndex] && number[startIndex] == number[midIndex]){
            return orderSearch(number, startIndex, endIndex);
        }

        //缩小查找范围
        if(number[startIndex] <= number[midIndex]){
            startIndex = midIndex;
        }
        else{
            endIndex = midIndex;
        }
    }
    return number[midIndex];
}

int orderSearch(int* number, int startIndex, int endIndex){
    int result = number[startIndex];
    for(int i=startIndex+1; i<=endIndex; i++){
        if(result > number[i]){
            result = number[i];
        }
    }
    return result;
}

测试用例

采用《剑指offer》提供的源码中的测试用例

/ ====================测试代码====================
void Test(int* numbers, int length, int expected)
{
    int result = 0;
    result = Min(numbers, length);

    for(int i = 0; i < length; ++i)
        printf("%d ", numbers[i]);

    if(result == expected)
        printf("\tpassed\n");
    else
        printf("\tfailed\n");

}

int main(void){
    // 典型输入,单调升序的数组的一个旋转
    int array1[] = {3, 4, 5, 1, 2};
    Test(array1, sizeof(array1) / sizeof(int), 1);

    // 有重复数字,并且重复的数字刚好的最小的数字
    int array2[] = {3, 4, 5, 1, 1, 2};
    Test(array2, sizeof(array2) / sizeof(int), 1);

    // 有重复数字,但重复的数字不是第一个数字和最后一个数字
    int array3[] = {3, 4, 5, 1, 2, 2};
    Test(array3, sizeof(array3) / sizeof(int), 1);

    // 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
    int array4[] = {1, 0, 1, 1, 1};
    Test(array4, sizeof(array4) / sizeof(int), 0);

    // 单调升序数组,旋转0个元素,也就是单调升序数组本身
    int array5[] = {1, 2, 3, 4, 5};
    Test(array5, sizeof(array5) / sizeof(int), 1);

    // 数组中只有一个数字
    int array6[] = {2};
    Test(array6, sizeof(array6) / sizeof(int), 2);

    // 输入NULL
    Test(NULL, 0, 0);
    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值