旋转数组的最小数字(二分)

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组 {3,4,5,1,2} 为 {1,2,3,4,5} 的一个旋转,该数组的最小值为1。

分析:

1, 2, 3, 4, 5 的一个旋转是 3, 4, 5, 1, 2,通过二分,5 与 3 、 5 与 2 比较,可以得出右边的子数组必定无序,故最小值一定在右边。

1, 2, 3, 4, 5 的另一个旋转是  5, 1, 2, 3, 4,用过二分,2 与 5 、 2 与 4比较,可以得出左边的子数组必定无序,故最小值一定在左边。

多尝试几个例子发现,最大值和最小值一定总在一起(本质因为数组的旋转),而这个导致了左右子数组的无序。

注:1, 1, 1, 0, 1 是特殊的例子,它的中间值与左右边界都相等,此时无法判断,但可以截取这段数组暴力地线性查找。

/*
 * 旋转数组的最小数字 
 */
int baoli(vector<int> arr, int a, int b)
{
    int ans = INF;
    for (int i = a; i <= b; i++)
    {
        if (ans > arr[i])
            ans = arr[i];
    }
    return ans;
}
int minNumberInRotateArray(vector<int> rotateArray)
{
    int left = 0, mid = 0;
    int right = rotateArray.size() - 1;
    while (left + 1 < right) {
         // 若边界不等,则二分(说明无序)
        mid = (left + right) >> 1;
        if (rotateArray[mid] < rotateArray[left]) {
            right = mid;
        }
        else if (rotateArray[mid] > rotateArray[right]) {
            left = mid;
        } // 若边界相等,暴力查找
        else {
            return baoli(rotateArray, left, right);
        }
    }
    return rotateArray[right];
}
int main()
{
    vector<int> rotateArray = {1, 1, 1, 0, 1};
    cout << minNumberInRotateArray(rotateArray) << endl;
    return 0;
}

从上面的代码可以看出有三条分支,分别是左子数组无序、右子数组无序、无法判断而线性查找三种情况。

注意循环的出口,此题中只剩下两个数时就能判断,此时需要直接跳出,否则程序会无限循环。

posted on 2020-04-16 21:32  Black_x  阅读(154)  评论(0编辑  收藏  举报