每日一练6.24/6.25——旋转数组的最小数字

旋转数组的最小数字

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

示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:

两种思路:

  1. O(n) 复杂度:遍历一遍,寻找降序点,输出降序点值,如果找不到,输出列表的首元素
  2. O(logn)复杂度:二分查找,注意分治方法,必须保证每次的规模都是减小的,而且要注意最后输出的是值而不是转折点的索引

# 第一种思路
def min_ele(nums):
    for i in range(1, len(nums)):
        if nums[i - 1] > nums[i]:
            return nums[i]
    return nums[0]

# 第二种思路
def min_element(nums):
    i = 0
    j = len(nums) - 1
    while i < j:
        mid = (i + j) // 2 # 左二分点,必有i <= mid < j
        if nums[mid] < nums[j]:
            j = mid
        elif nums[mid] > nums[j]:
            i = mid + 1   # 必须是mid + 1, 不能是mid,保证规模减小
        else:
            j -= 1  # 分析见后文
    return nums[i]
       

关于nums[mid] == nums[j]的分析:

  1. 如果mid在左序列,则nums[i, mid]j上的值都是相等的。进一步,若j不是旋转点,则旋转点在[i, j - 1]中。若j是旋转点,则[i, j - 1]为递增序列,继续走下去会输出序列首,并且序列首的值和旋转点的值相等。
  2. 如果mid在右序列,则旋转点在[i, mid]mid < j,从而在[i, j - 1]中。

实现代码中的问题:

  1. 二分法三点:改变左右索引,保证规模减小,并且最终值在区间中。
  2. 通常使用while i < j的模式实现。如果用递归写,也可以,但是比较麻烦,逻辑上也不好处理变化。
  3. 比较时使用起点或者终点作为基准点,而不是中间点周围的点如mid + 1, 那样会把问题搞复杂。
  4. 对于nums[mid] == nums[j]的讨论具有技巧,注意把握。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章