春招打卡|旋转数组中的最小数字

82 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。

例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为1。

二、思路分析

  1. 寻找旋转数组中的最小值,首先可以考虑到的是遍历数组,如果当前元素比最小数值小,则替换最小数值为当前元素。
  2. 遍历的做法无法体现出旋转数组的性质,可以考虑从后向前遍历,如果当前元素比最小数值小则替换最小数值,如果当前元素比前一个元素大,则代表到达了旋转点,停止遍历。如果数组有一半数据是旋转的,那么遍历的元素个数可以降低一半。
  3. 第三种做法为二分查找,中间元素大于右边的数据,则更新l下标将其替换为mid+1,在右侧区间内搜索。mid+1是因为左侧为旋转数组+1后不影响继续遍历,如果中间元素大于左边的数据,则将r更新为mid,在左侧搜索,由于数组中有重复数据,不可以抛弃该数据,也就不能赋值为mid-1。

三、AC 代码

一次遍历

func minArray(numbers []int) int {
    min := math.MaxInt32
    for i := 0;i < len(numbers);i++ {
        if min > numbers[i] {
            min = numbers[i]
        }
    }
    return min
}

尾部遍历

func minArray(numbers []int) int {
    //尾指针
    n := len(numbers)
    min := numbers[n-1]
    for i := n-1;i >= 0 ;i-- {
        if min >= numbers[i] {
            min = numbers[i]
        } else{
            return min
        }
    }
    return min
}

二分查找

func minArray(numbers []int) int {
    l,r := 0,len(numbers) - 1
    for l < r {
        mid := l +(r-l)/2
        if numbers[mid] > numbers[r] {
            l = mid + 1
        }else if numbers[mid] < numbers[r] {
            r = mid
        }else{
            r--
        }
    }
    return numbers[l]
}

四、总结

一次遍历复杂度为O(n),尾部开始遍历复杂度不稳定,会根据遍历数组的情况不同发生改变。二分查找时间复杂度为O(log2n)。