• [剑指Offer] 旋转数组的最小数字


    问题描述

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

    NOTE:给出的所有元素都大于0,若数组大小为0,请返回0

    分析

    思路一

    记录当前元素cur的前一个元素pre,当cur < pre的时候,cur就是最小的元素,时间复杂度为(O(n))

    int minNumberInRotateArray(vector<int> rotateArray) {
        int len = rotateArray.size();
        if (len == 0) return 0;
        int pre = rotateArray[0];
        for(int i = 0; i < len; ++i) {
            if (rotateArray[i] < pre) {
                return rotateArray[i];
            }
    
            pre = rotateArray[i];
        }
    }
    

    思路二

    借鉴二分查找的思想,数组旋转后被分为两部分
    low 指向 左部分, high指向右部分
    左右部分的分界点就是最小值

    通过不断地缩小[low, high]的范围,最终low指向左部分最后一个元素,high指向右部分第一个元素,也就是最小值

    这样做能在牛客AC但其实是错的,无法通过{1, 0, 1, 1, 1}的检验

    int minNumberInRotateArray(vector<int> rotateArray) {
        if (rotateArray.size() == 0) return 0;
        int low = 0, high = rotateArray.size() - 1;
        int mid = 0;
    
        // 数组有序时直接返回首元素
        if (rotateArray[0] < rotateArray[high]) {
            return rotateArray[0];
        }
    
        while (low < high-1) {
            mid = (low + high) / 2;
            if (rotateArray[mid] > rotateArray[low]) {
                low = mid;
            } else if (rotateArray[mid] < rotateArray[high]){
                high = mid;
            } else {
                ++low;
            }
        }
    
        return rotateArray[high];
    }
    

    这道题的坑很多,牛客网上的测试用例不够完善,这里自己增加了一些特殊的测试用例,参考(chao xi)了大佬的代码才通过了所有的测试用例

    {1, 1, 1, 1, 1}
    {1, 0, 1, 1, 1}
    {3, 4, 5, 1, 2} // 普通
    {1, 2, 3, 4, 5} // 旋转0
    

    这种做法的low并不会固定在数组的左部分,由于rotateArray[mid] > rotateArray[low]时的处理是low = mid + 1,low有可能会到数组的右部分第一个元素,这时对数组[low, high]部分的有序判断将返回数组的min

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int minNumberInRotateArray(vector<int> rotateArray)
    {
        if (rotateArray.size() == 0) return 0;
        int low = 0, high = rotateArray.size() - 1;
        int mid = 0;
    
        while (low < high) {
            // 数组有序时直接返回首元素,low可能指到右部分的第一个元素(也就是min)
            if (rotateArray[low] < rotateArray[high]) {
                return rotateArray[low];
            }
            mid = (low + high) / 2;
            if (rotateArray[mid] > rotateArray[low]) {
                low = mid + 1; // 配合上面rotateArray[low] < rotateArray[high]的判断,能处理{1, 0, 1, 1, 1}
            } else if (rotateArray[mid] < rotateArray[high]){
                high = mid;
            } else {
                ++low;
            }
        }
    
        return rotateArray[low];
    }
    
    int main()
    {
        int a1[] = {1, 1, 1, 1, 1};
        int a2[] = {1, 0, 1, 1, 1};
        int a3[] = {3, 4, 5, 1, 2}; // 普通
        int a4[] = {1, 2, 3, 4, 5}; // 旋转0
    
        vector<int> input1(a1, a1+5);
        vector<int> input2(a2, a2+5);
        vector<int> input3(a3, a3+5);
        vector<int> input4(a4, a4+5);
    
        cout << minNumberInRotateArray(input1) << " expected: 1" << endl;
        cout << minNumberInRotateArray(input2) << " expected: 0" << endl;
        cout << minNumberInRotateArray(input3) << " expected: 1" << endl;
        cout << minNumberInRotateArray(input4) << " expected: 1" << endl;
    }
    

    References

    1. 旋转数组的最小数字__牛客网
  • 相关阅读:
    你理解的软件测试是什么?将决定你的工作内容和工作方式。
    测试一个域名DNS查询时间的shell脚本
    Iptables 防火墙开放常见的22,53,80端口
    linux服务器查看公网IP信息的方法
    SQL server 2016 安装步骤
    Thinkpad 笔记本VMware Workstation 安装虚拟机出现“此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态”解决方法
    Real-Time Loop Closure in 2D LiDAR SLAM论文解读
    前端开发学习路线
    服务器开发学习路径
    讲义和教材的区别
  • 原文地址:https://www.cnblogs.com/arcsinw/p/12953456.html
Copyright © 2020-2023  润新知