剑指offer 11 -旋转数组中最小数字 - python

92 阅读2分钟

题目描述:

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

给出的所有元素都大于0,若数组大小为0,请返回0。

示例 1:

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

示例 2:

输入:[2,2,2,0,1]
输出:0

  • 线性搜索: 根据题目要求分别考虑数组为空、数组只有一个元素和数组包含多个元素考虑,当数组为空返回0;当数组只有一个元素则直接返回该元素;若数组包含多个元素,则依次遍历数组找到最小元素即可

  • 二分查找: 不管题目给定的是原数组还是旋转数组,本质上都是求数组中的最小元素。因此,只要数组中的元素不改变,任何的查找算法都可以使用。例如 A = { 3 , 4 , 5 , 1 , 2 } A = \{3,4,5,1,2\} A={3,4,5,1,2}类的旋转数组可以分为左右两个子数组,因此可以采用二分查找的方法:

    • 如果 A [ m i d − 1 ] < A [ m i d ] < A [ m i d + 1 ] A[mid - 1] < A[mid] < A[mid + 1] A[mid−1]<A[mid]<A[mid+1],说明当前元素并不是最小的,设置 r i g h t = m i d − 1 right = mid - 1 right=mid−1, l e f t left left不变
    • 如果 A [ m i d − 1 ] > A [ m i d ] < A [ m i d + 1 ] A[mid - 1] > A[mid] < A[mid + 1] A[mid−1]>A[mid]<A[mid+1],说明当前元素就是查找的元素
    • 因为数组保持递增,因此不存在 A [ m i d − 1 ] > A [ m i d ] > A [ m i d + 1 ] A[mid - 1] > A[mid] > A[mid + 1] A[mid−1]>A[mid]>A[mid+1]的情况
  • 寻找突变点:题目给定的原数组本身就是递增,因此旋转后的数组存在一个突变点,而这个突变点就是数组中的最小元素。因此,题目求解就转换为了寻找突变点的过程。从索引0开始

    • 如果 r o t a t e A r r a y [ i ] > r o t a t e A r r a y [ i + 1 ] rotateArray[i] > rotateArray[i + 1] rotateArray[i]>rotateArray[i+1],说明下一个元素就是数组中的最小值
    • 如果遍历到头还没有满足条件的元素,那么说明第一个元素就是最小值

线性搜索

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if rotateArray == []: return 0
        if len(rotateArray) == 1: return rotateArray[-1]
        
        minNum = rotateArray[0]
        for i in range(1,len(rotateArray):
            if rotateArray[i] < minNum:
                minNum  = rotateArray[i]
 
        return minNum 

二分查找

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
    	l = len(rotateArray)
        if l == 0: return 0
        if l == 1: return rotateArray[-1]
            
        left = 0
        right = l - 1 
        while left < right: 
            mid = (left + right) // 2
            if rotateArray[mid] > rotateArray[right]:
                left = mid + 1
            elif rotateArray[mid] == rotateArray[right]:
                right = right - 1
            else:
                right = mid
    
        return rotateArray[left]

寻找突变点

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        l = len(rotateArray)
        if l == 0:
            return 0
        if l == 1:
            return rotateArray[-1]
        
        for i in range(l):
            if rotateArray[i] > rotateArray[i + 1]:
                return rotateArray[i + 1]
        
        return rotateArray[0]