• 【LeetCode】面试题11. 旋转数组的最小数字


    题目:

    思路:

    关于旋转数组有各种变种问题:是否有重复元素、寻找最大值最小值、寻找旋转点下标(旋转点的值等于最小值)、查找给定元素。本题就是对有重复元素的旋转数组,寻找其最小值。
    首先想到二分查找没问题,关键在于怎么通过判断middle元素的相对大小去逐渐缩小搜索区间。如下图所示(无重复元素)

    • 循环二分,middle = (left + right) // 2(向下取整)为每次二分的中点,恒有left <= middle < right

      • 当num[middle] < num[right],middle处于右边序列,旋转点一定在[left, middle]闭区间内,因此执行right = middle(不是middle-1,因为middle有可能是旋转点)
      • 当num[middle] > num[right],middle处于左边序列,旋转点一定在[middle+1, right]闭区间内,因此执行left = middle+1(middle肯定不是旋转点)
      • 当num[middle] = num[right],无法判断middle处于哪边序列,执行right = right-1,证明该操作的正确性只需证明操作后旋转点仍然在[left, right]区间内即可
        • 若middle在右边序列,则[middle, right]区间内所有元素相等,执行right = right-1只会抛弃一个重复值,旋转点仍然在[left, right]区间
        • 若middle在左边序列,由于左边序列任一元素 >= 右边序列任一元素,因此可推出旋转点num[x] <= num[right] = numb[middle],并且[left, middle]区间内所有元素相等
          • 若num[x] < num[right],则right左边仍有更小的元素(最小值位于左边序列),执行right = right-1之后,旋转点仍然在[left, right]区间
          • 若num[x] = num[right],则左边序列所有元素相等,并且等于[left, middle]区间内的元素
            • 若right > x,执行right = right-1后,旋转点仍然在[left, right]区间
            • 若right = x,执行right = right-1后,旋转点不在区间内,但返回的num[0]仍然是最小值。因为之后的二分循环一直在执行right = middle,而区间[left, middle]内的元素值一定都等于旋转点的值也就是最小值
    • 返回值,当left = right时跳出循环,返回num[left]即可

    • 特殊情形

      • [1, 0, 1, 1, 1],middle = 2在右边序列
      • [1, 1, 1, 0, 1],middle = 2在左边序列
      • [1, 1, 1, 2, 3, 1],跳过旋转点,返回num[0]
      • [1, 2, 3, 4, 5],可以认为从头到尾全部旋转,寻找最大值时相当于右边序列为空,寻找最小值时相当于左边序列为空
    • 寻找最小值时不可以让num[middle]和num[left]进行对比,因为对比的目的是判断middle处于哪边序列,当只有一个序列时会出现问题。寻找最大值时和num[left]比较,寻找最小值时和num[right]比较。

    • 误区: 判断middle处于哪边序列中时,只需要和一边比较就可以,不需要同时比较left和right。从结果上看其实并不需要很复杂很多的判断条件,一开始判断条件过多容易混乱,需要从多种条件中抽离出关键点。

    代码:

    Python

    class Solution(object):
        def minArray(self, numbers):
            """
            :type numbers: List[int]
            :rtype: int
            """
            left = 0
            right = len(numbers) - 1
            while left < right:
                middle = (left + right) // 2
                if numbers[middle] > numbers[right]:
                    left = middle + 1
                elif numbers[middle] < numbers[right]:
                    right = middle
                else:
                    right = right - 1
            return numbers[left]
    

    相关问题

  • 相关阅读:
    1. Ubuntu下使用pip方式安装tensorflow
    CSS 属性
    django运行django-admin.py无法创建网站
    jQuery各种效果举例
    一生莫轻舞,一舞一生苦
    即使你美丽动人,也要具备更华丽的着装
    即使有一颗强大的心,也要让人看到你美丽的外表
    python操作RabbiMQ
    windows下python安装paramiko
    python用paramiko将执行的结果存入excel表格
  • 原文地址:https://www.cnblogs.com/cling-cling/p/12935855.html
Copyright © 2020-2023  润新知