zoukankan      html  css  js  c++  java
  • 二分搜索应用(旋转数组)——C语言

        出处——《剑指offer》

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

        1.用遍历数组的方法来实现

    int MinInOrder( int num[], index1, index2 )        /*index1为数组起始位置,index2为数组终止位置*/

    {

        int result = num[ index1 ];

        int i;

        for( i = index1 + 1; i <= index2; i++ )

        {

            if( result > num[i] )

                result = num[i];

        }

        return result;

    }

        算法复杂度O(n)

        2.若能够使用二分搜索实现可以使算法复杂度为O(logn)

        书中有详细的讲解,跟一般的二分搜索类似,但由于不是查找特定的数,而是要找到最小的数,因此要找到如何能够确定最小数的方法。根据旋转数组的特点,可以将其看作两个递增数组的组合,且左边数组的所有元素都大于右边数组,最小数所在的位置为右边数组的第一位。

        设定三个指针i1,i2以及mid,使得i1始终处在左边数组中,i2始终处在右边数组中, mid为中间数,通过i1,i2,mid元素间的大小关系来逐步确定最小数的位置。

        例如:若num[mid] >= num[i1]表明mid在左边数组中,那么令i1 = mid就可以使得i1趋近于左边数组末尾;若num[mid] <= num[i2]表明mid在右边数组中,此时则可令i2 = mid。

        最终当i2 - i1 == 1时,i2就为最小元素的位置。

    int Min( int num[], int length )        /*length为数组长度*/

    {

        int i1, i2, mid;

        i1 = 0;

        i2 = length - 1;

        while( num[i1] >= num[i2] )        /*保证i1,i2处在不同的子数组中*/

        {

            if( i2 - i1 == 1 )

                return num[i2];

            mid = ( i1 + i2 ) / 2;

            if( num[mid] >= num[i1] )

                i1 = mid;

            if( num[mid] <= num[i2] )

                i2 = mid;

        }

        return num[i1];        /*完全递增的数组也是旋转数组的一种,当出现这种情况时,由于num[i1] < num[i2]使得循环不执行,此时返回数组首元素*/

    }

        不过上面的程序面对一些特例时会出现问题,如数组{ 1, 0, 1, 1, 1 },会出现num[i1] = num[i2] = num[mid] = 1的情况,此时循环中的两个if语句中的判断条件都为真,因此当第一次循环结束后就会出现i1 = i2 = mid的情况,使得循环无限执行。因此需要将这种情况考虑到函数中。

    int Min( int num[], int length )      

    {

        int i1, i2, mid;

        i1 = 0;

        i2 = length - 1;

        while( num[i1] >= num[i2] )       

        {

            if( i2 - i1 == 1 )

                return num[i2];

            mid = ( i1 + i2 ) / 2;

            if( num[i1] == num[i2] && num[i1] == num[mid] )        /*出现i1, i2, mid三个元素都相等的情况则采用顺序搜索的方法*/

                return MinInOrder( num, i1, i2 );

            if( num[mid] >= num[i1] )

                i1 = mid;

            if( num[mid] <= num[i2] )

                i2 = mid;

        }

        return num[i1];        

    }

  • 相关阅读:
    setTimeout详解
    【康娜的线段树】
    【[CQOI2016]手机号码】
    【[IOI2014]Wall 砖墙】
    【[1007]梦美与线段树】
    【[POI2010]ANT-Antisymmetry】
    【[HEOI2016/TJOI2016]排序】
    【[SCOI2016]背单词】
    【[HNOI2008]GT考试】
    【[JSOI2007]建筑抢修】
  • 原文地址:https://www.cnblogs.com/liangchao/p/2682076.html
Copyright © 2011-2022 走看看