题解 | #旋转数组的最小数字#

旋转数组的最小数字

http://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba

解题思路:

有序的序列进行查找,优先想到二分查找,那先复习一下二分查找:

二分查找的条件:
  1. 查找的内容在逻辑上来说是有序的;
  2. 查找的数量只能是一个。
二分查找的过程:
  1. 首先确定查找元素的中间的位置mid=(left+right)/2;
  2. 如果中间的元素与要查找的元素target相同,说明找到了,返回中间元素的坐标;
  3. 如果中间元素的值小于要查找元素的值,因为有序,所以target在中间元素的左边是不可能,target只可能在中间元素的右边,所以将查找范围缩小到[mid+1,right];
  4. 如果中间元素的值大于要查找元素的值,target只可能出现在中间元素的左边,所以将查找范围缩小到[left,mid-1];
  5. 重复上述过程,直到left的值大于right的值,如果没有找到,返回-1。
二分查找的时间复杂度:O(logn)
二分查找的空间复杂度:O(1)

二分查找代码如下,基于C++实现的:


class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size()-1;
        int mid;
        while(left <= right){
            mid = (left + right)/2;
            if(nums[mid]==target){
                return mid;
            }else if(nums[mid] > target){
                right = mid-1;
            }else{
                left = mid+1;
            }
        }
        return -1;
    }
};

对于该题目有一个旋转的限制条件,那就考虑修改二分查找。

  1. 分别用两个指针left和right指向数组的第一个元素和最后一个元素,按照题目中旋转的规则,第一个元素的值应该大于或者等于最后一个元素的值,如果第一个元素的值小于最后一个元素的值,那么原数组是没有进行反转的递增数列,直接返回数组的第一个元素即可。
  2. 接着我们和二分查找一样找到中间位置mid的元素,如果中间元素位于前面递增的子数组,那最小值将存在于[mid,right]之间,我们考虑将left的位置移到mid的位置,这样[left,right]又是一个旋转的数组;同样,当中间元素位于后边的递增序列,那最小值将存在于[left,mid]之间,考虑将right的位置移动到mid的位置,[left,right]又是一个旋转区间。
  3. 重复上边的操作,最后我们会得到只有两个元素的[left,right]区间,right位置对应的的元素即为最小值。
  4. 特殊情况,当序列为[5,1,2,5,5,5,5,5,5]这种特殊类型时,在判断left,right,mid时,三者相等,就无法使用二分查找进行移动,我们可以考虑使用顺序查找的方法。
时间复杂度:最坏的时候是对应的特殊情况为O(n),平均就是二分查找的时间复杂度O(logn);
空间复杂度:O(1);

代码是基于C++实现的:

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int left = 0, right = rotateArray.size()-1;
        //mid初值为left,当序列没有进行旋转时,直接返回left
        int mid = left;
        while(left <= right && rotateArray[left] >= rotateArray[right]){
            //循环结束的条件,只剩两个元素
            if(right - left == 1){
                mid = right;
                break;
            }
            mid = (left + right)/2;
            //注意不要写成rotateArray[left] == rotateArray[right] == rotateArray[mid],这样是错误的
            if(rotateArray[left] == rotateArray[right] && rotateArray[left] == rotateArray[mid]){
                return minInOrder(rotateArray, left, right);
            }
            if(rotateArray[mid] >= rotateArray[left]){
                left = mid;
            }else if(rotateArray[mid] <= rotateArray[right]){
                right = mid;
            }
        }
        return rotateArray[mid];
    }
    int minInOrder(vector<int> rotateArray, int left, int right){
        int result = rotateArray[left];
        for(int i=left+1; i<=right; i++){
            if(result > rotateArray[i]){
                result = rotateArray[i];
            }
        }
        return result;
    }
};
全部评论

相关推荐

头像
04-27 15:11
已编辑
华东师范大学 算法工程师
暑期实习从2月开始投,面了两个月,流程该挂的都挂完了,腾讯字节一共号称是1.7w个hc,不知道都发给谁了,估计今年秋招要难顶。Timeline米哈游、美团、蚂蚁、微软等公司直接简历挂穿,没进面。携程:3.3&nbsp;投递、测评3.12&nbsp;笔试3.18&nbsp;一面3.25&nbsp;二面4.13&nbsp;ai面(hr面)4.14&nbsp;英语测评4.23&nbsp;offer(已拒)腾讯:2.6&nbsp;测评2.28&nbsp;wxg一面3.5&nbsp;wxg二面(挂)3.11&nbsp;teg一面3.21&nbsp;teg二面(取消)3.31&nbsp;teg一面4.10&nbsp;teg二面(挂)4.21&nbsp;wxg一面4.24&nbsp;wxg二面(挂)字节:1.28&nbsp;aml约面(取消)3.17&nbsp;火山一面(挂)4.8&nbsp;aml一面(挂)4.20&nbsp;抖音data一面(挂)阿里:3.23&nbsp;投递、测评3.28&nbsp;笔试3.31&nbsp;淘天一面4.8&nbsp;钉钉一面4.9&nbsp;淘天二面4.10&nbsp;阿里控股一面4.12&nbsp;钉钉二面(取消)4.15&nbsp;淘天hr面4.16&nbsp;淘天offer(已接)4.21&nbsp;高德一面(取消)4.22&nbsp;淘宝闪购一面(取消)面试最大的感触是,现在撞上ai转型,一堆老业务急着转向,新业务非常不成熟,研究型的组bar非常高根本进不去,业务侧挂着算法的岗位干的都是工程活,面试却又要问算法,另外agent的落地也远没有那么广,绝大多数还是那套写死的系统调一下llm&nbsp;api或者做做rag,其余少部分真的在搭agent的,基本不能在线上服务用什么很智能的模型,现阶段成本太高,进去大概率就是给垃圾模型从工程方面兜底,除了业务场景的应用和数据经验以外,技术方面很难有什么提升。算法岗做不了基模的还是去搜广推好,之前判断失误了完全没投,秋招不知道还进不进得去。
嵌入式的小白:不错啊,淘天也是挺好的,恭喜
我的求职进度条
点赞 评论 收藏
分享
03-31 14:46
已编辑
门头沟学院 Web前端
励志成为双港第一ja...:这其实很正常,离的太远了,他认为你不会来,就为了混个面试,而且成本很高,实习生都优先选本地高校。吃了地域的亏,所有很多时候地域可能比院校层次更重要。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务