【旋转数组的最小数字】-C语言-题解

本题来源于牛客网,原题链接如下:
旋转数组的最小数字

描述:

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。
请问,给定这样一个旋转数组,求数组中的最小值。

数据范围:

1≤n≤10000

数组中任意元素的值:

0≤val≤10000

题解:

1. 解法一:BF解法
暴力破解,从旋转后的数组的最后一位开始往前找,直到找到最小值
具体找的方法是:从数组的第n项开始,与前一项进行对比。
由题目旋转数组的性质可知,因为旋转前是非降序数组,故旋转后的数组从最后一项开始,其前一项要么小于最后一项,要么等于最后一项。若当某一项的前一项大于该项,则说明该项就是要找的最小值。

那么我们就可以创建一个临时变量来保存较小者,当前一项大于后一项时结束循环(可通过创建标记变量来实现),此时临时变量的值即为最小值。

  • 完整代码如下
int minNumberInRotateArray(int* rotateArray, int rotateArrayLen ) 
{
   int len = rotateArrayLen - 1;
   int tmp = rotateArray[len];//从最后一个元素开始
   int flag =  1;
   while(flag && len)   
   {
        if(tmp == rotateArray[len-1])
        len--;                          //若相等继续往前进行比较
        else if(tmp > rotateArray[len-1])//让tmp为小的,继续和前面的比较
        {
            tmp = rotateArray[len-1];
            len--;
        }
        else if(tmp < rotateArray[len-1])//当前tmp即为最小
        flag = 0;
   }
   return tmp;
}

2. 解法二:二分法
结合二分法的思想,旋转后的数组中间位置上的数要么是原数组中未旋转的部分中的数(如例中3 4 5 1 2 中的 5);要么是已旋转部分中的数(如例中 4 5 1 2 3 中的 1 )。那么就可循环通过中间位置上的数与最右边的数进行比较,逐步将查找范围缩小。
每次对比可分为一下3种情况:
设标记

    int left = 0;
    int right = rotateArrayLen - 1;
    int mid = (left + right) / 2;

(1)中间数大于最右边:此时的中间数一定是原数组中的未旋转部分中的数(如:3 4 5 1 2),即最小的数一定在中间数右边,那么此时就可将左边界 left 的值置为 mid + 1,缩小查找范围。
(2)中间数等于最右边:此时的最小数要么就是中间数(如:2 2 2 2 2),要么就是在中间数的左边(如:1 0 1 1 1),故通过让右边界 right- -来缩小范围,此时相当于mid(= right + left / 2)的值减小了,即 mid 往左“移”了,相对地,最小的数就往右推了。
(3)中间数小于最右边:此时的中间数一定是原数组中的旋转部分中的数,即最小的数一定在中间数左边(如:5 1 2 3 4)或者直接就是中间数(如4 5 1 2 3),故此时可将右边界 right 的值置为 mid 来缩小范围

查找结束的条件:当左边界 left = 右边界 right,此时下标 left 对应的数组元素 或 下标 right 对应的数组元素就是要找的最小的数
这里用 4 5 1 2 3 作为例子:
第一次查找:
初始时,mid对应值为1,比最右边数小,比较后执行 right = mid;查找范围缩小到4 5 1
第二次查找:
mid对应值为5,比最右边数大,比较后执行 left = mid + 1;此时 left = right,查找结束。

  • 完整代码如下:
int minNumberInRotateArray(int* rotateArray, int rotateArrayLen ) 
{
    int left = 0;
    int right = rotateArrayLen - 1;
    int mid = 0;
    while(left < right)
    {
        mid = (left + right) / 2;
        if(rotateArray[mid] > rotateArray[right])
        {
            left = mid + 1;
        }
        else if(rotateArray[mid] == rotateArray[right])
        {
            right--;
        }
        else if(rotateArray[mid] < rotateArray[right])
        {
            right = mid;
        }
    }
    return rotateArray[left];
}

看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或看不懂的地方或有可优化的部分还恳请朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值