[剑指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. 旋转数组的最小数字__牛客网
posted @ 2020-05-24 23:12  arcsinW  阅读(94)  评论(0编辑  收藏  举报