旋转数组的最小数字

旋转数组的最小数字(点击链接进入题目)

描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
示例1
  输入:[3,4,5,1,2]
  返回值:1

法一:线性遍历,定义一个min变量用来存储最小值,然后遍历数组,遇到小的就更新min,最后输出min。代码较简单,但是时间复杂度为O(N)。不推荐。

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int min = rotateArray[0];
        for(const auto& val : rotateArray)
        {
            if(val < min)
                min = val;
        }
        return min;
    }
};

法二:定义两个变量slow和fast,指向数组的前两个元素,依次比较slow和fast,如果slow <= fast,则slow++,fast++,如果遇到slow > fast,则fast就是我们要找的值,这个和法一 一样,没有优化多少,遇到极端情况,比如最小的数在最后面,也是O(N)级别的。
在这里插入图片描述
但是当数组是如下情况时,就会出现问题。所以我们加入一个标志位flag,当slow和fast一直往后移,仍没有slow>fast时,就输出数组的第一个元素。
在这里插入图片描述

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.size() == 0)
            return 0;
        
        int flag = 0;
        int slow = 0;
        int fast = slow + 1;
        while(fast < rotateArray.size())
        {
            if(rotateArray[slow] <= rotateArray[fast])
            {
                slow++;
                fast++;
                flag = 1;
            }
            else
                return rotateArray[fast];
        }
        if(flag != 0)
            return rotateArray[0];
        else
            return 0;
    }
};

法三:根据法二的分析,我们知,不管我们怎样旋转,一定会将数组分为两部分,每一部分都是非递减的排序数组,而且前半部分数组的值整体大于后半部分,而我们要找的结果在数组中间位置的左边或者右边所以本题我们可以借鉴二分查找,定义一个start和end,在定义一个int mid = (start + end)>>1。我们旋转的深或者浅,最小的值要么在mid左边要么在mid右边,要么就是mid,如果arr[mid] < arr[start],说明arr[mid]是属于后半部分数组的,所以要找的值在前半部分数组,right = mid,如果arr[mid] >= arr[start],说明arr[mid]和arr[start]共同属于前半部分数组的,所以要找的值在后半部分数组的开头,left = mid,这个过程,会让[left, right]区间缩小

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        //如果数组的大小为0,则返回0
        if(rotateArray.empty())
            return 0;
            
        //定义start和end,分别指向数组的最左边和最右边,并定义一个mid变量表示中间值
        int start = 0;
        int end = rotateArray.size() - 1;
        int mid = 0;
        //只有当数组最左边的元素大于最右边的元素时,才进入循环
        //如果不满足就对应法二中的图二的情况,此时直接返回数组中首位置的元素
        while(rotateArray[start] >= rotateArray[end])
        {
            //如果只有1个元素应该怎么办,只有一个元素,说明该值即最右边的元素就是我们要找的值
            if(end - start == 1)
            {
                mid = end;
                break;
            }
            
            //计算mid
            mid = ((start + end) >> 1);
            
            //如果mid、left、right三个位置上的值相等,我们是无法区分左右两个数组的
            //此时我们只能通过线性的方法,遍历整个数组去寻找
            if(rotateArray[mid] == rotateArray[start] && rotateArray[start] == rotateArray[end])
            {
                //直接遍历去找
                int ret = rotateArray[start];
                for(int i = start + 1; i < end; i++)
                {
                    if(ret  > rotateArray[i])
                        ret = rotateArray[i];
                }
                return ret;
            }
            
            //如果arr[mid] >= arr[start],说明arr[mid]和arr[start]共同属于前半部分数组的
            //所以要找的值在后半部分数组的开头,start= mid
            if(rotateArray[mid] >= rotateArray[start])
                start = mid;
            //如果arr[mid] < arr[start],说明arr[mid]是属于后半部分数组的
            //所以要找的值在前半部分数组,end= mid
            else
                end = mid;
        }
        return rotateArray[mid];
    }
};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

做1个快乐的程序员

感谢支持,一起加油努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值