《剑指Offer》读书笔记06:旋转数组的最小数字


题目描述

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


解题思路

  1. 简单直接粗暴方法:从头至尾遍历数组,找出最小元素,时间复杂度O(n).
  2. 排序数组中可以用二分查找法(时间复杂度O(log n)),此旋转数组基本有序。
  3. 用left和right指向数组第一个和最后一个元素。按旋转数组规则,第一个元素应该大于或者等于最后一个元素。找到中间元素middle。若middle元素大于等于left元素,前半部分递增,最小元素在后半部分,将left移至middle位置;若middle元素小于等于right元素,后半部分递增,最小元素在前半部分,将right移至middle位置。 这样就能缩小一半的范围,然后重新做新一轮查找。
  4. 最后left指向前面子数组的最后一个元素,right指向后面子数组的第一个元素,两者相邻,right所指元素为最小元素,循环结束。
  5. 特殊情形一,原数组的旋转了0个或n个元素,旋转数组与原数组相同,此时最小元素在最前面。
  6. 特殊情形二,当left,right和middle均相同时,无法判断middle元素位于前半部分还是后半部分。如原数组{0,1,1,1,1,1},其旋转数组{1,0,1,1,1,1}和{1,1,1,1,0,1}无法判断。此时需要暴力顺序查找。

参考代码

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if ( rotateArray.empty() ) {
            //throw new std::exception("Invalid parameters!");
            return 0;
        }

        int left = 0;
        int right = rotateArray.size()-1;
        int middle = left;//应对特殊情形一,left所指小于right所指,跳过while循环。

        while (rotateArray[left] >= rotateArray[right] ) {
            if ( right - left == 1 )  {
                middle = right;
                break;
            }

            middle = (right+left)/2;

            if ( rotateArray[middle] == rotateArray[left] //特殊情形二
                && rotateArray[middle] == rotateArray[right] ) {
                return minNumberInOrderArray(rotateArray, left, right);
            }

            if ( rotateArray[middle] >= rotateArray[left] ) {
                left = middle;
            } else if ( rotateArray[middle] <= rotateArray[right] ) {
                right = middle;
            }
        }
        return rotateArray[middle];
    }

    //顺序查找
    int minNumberInOrderArray(vector<int> rotateArray, int left, int right) {
        int minNumber = rotateArray[left];
        for ( int i = left+1; i <= right; i++ ) {
            if ( minNumber > rotateArray[i] ) {
                minNumber = rotateArray[i];
            }
        }
        return minNumber;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值