美文网首页剑指Offer-Python-牛客网
面试题11:旋转数组的最小数字

面试题11:旋转数组的最小数字

作者: 凌霄文强 | 来源:发表于2019-01-05 14:40 被阅读0次

    题目描述

    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

    知识点

    排序,折半查找


    Qiang的思路

    对于这道题,如果不管是不是排序,旋转之类的,直接通过遍历就能得到结果,但是显然这样做就没什么意义了。同样也说明,这道题考察的是如何将时间复杂度降低。遍历的时间复杂度为O(n),因为排好序了,所以可以使用折半查找,时间复杂度为O(logn)。

    我们能够发现数组一共有三种情况:

    • 长度为0。
    • 没有旋转,这算是旋转中的一种特殊情况。
    • 正常旋转。

    对于第一种情况,只需要返回0即可。对于第二种情况只需要返回第一个值即可,此时第一个元素一定小于最后一个元素。对于第三种情况才是需要使用递归执行的。

    既然想使用折半查找的办法去做,那么首先要分析一下中间值的特点。显然,中间值可能有几种情况:

    • 大于开头和结尾。也就是说中间值还在旋转之后的前部分。这种情况下最小值一定在后半部。
    • 小于开头和结尾。中间值在后部分。此时最小值一定在前半部。
    • 等于开头和结尾。这个时候无法确定最小值所在的区域,也就是说折半查找在这种情况下是行不通的。
    • 等于开头,不等于结尾。此时结尾一定小于中间值的,所以最小值在后面部分。
      -等于结尾,不等于开头。此时开头大于中间值,所以最小值一定在前半部分。

    组合一下上面的五种情况:

    • 当中间值等于开头和结尾是采用遍历查找。
    • 当中间值大于等于开头,在后半部继续查找。(中间值不用考虑)
    • 当中间值小于等于结尾,在前半部查找。(中间值需要考虑)

    所以能写出如下的代码:

    # -*- coding:utf-8 -*-
    class Solution:
        def minNumberInRotateArray(self, rotateArray):
            # write code here
            if len(rotateArray)==0:
                return 0
            while rotateArray[0]>=rotateArray[-1]:
                if len(rotateArray)==2:
                    return min(rotateArray)
                mid=int(len(rotateArray)/2)
                if rotateArray[0]==rotateArray[-1] and rotateArray[0]==rotateArray[mid]:
                    return min(rotateArray)
                if rotateArray[mid]>=rotateArray[0]:
                    rotateArray=rotateArray[mid+1:]
                elif rotateArray[mid]<=rotateArray[-1]:
                    rotateArray=rotateArray[:mid+1]
            return rotateArray[0]
    

    这个问题中有几点需要注意:

    • 当没有旋转或者是检查的串是非递减时(第一项小于最后一项),这种情况需要单独考虑。
    • 当第一项,中间一项和最后一项三者相同时,此时是特殊情况,只能通过遍历的方式计算。

    作者原创,如需转载及其他问题请邮箱联系:lwqiang_chn@163.com
    个人网站:https://www.myqiang.top

    相关文章

      网友评论

        本文标题:面试题11:旋转数组的最小数字

        本文链接:https://www.haomeiwen.com/subject/gmurrqtx.html