写点什么

每日一题:LeetCode-153. 寻找旋转排序数组中的最小值

作者:半亩房顶
  • 2024-01-19
    北京
  • 本文字数:1478 字

    阅读完需:约 5 分钟

每日一题:LeetCode-153. 寻找旋转排序数组中的最小值

刷题使我快乐,满脸开心.jpg



题目

已知一个长度为 n 的数组,预先按照升序排列,经由 1n旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]]


给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素


你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。


示例 1:


输入:nums = [3,4,5,1,2]输出:1解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。
复制代码


示例 2:


输入:nums = [4,5,6,7,0,1,2]输出:0解释:原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。
复制代码


示例 3:


输入:nums = [11,13,15,17]输出:11解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。
复制代码


提示:


  • n == nums.length

  • 1 <= n <= 5000

  • -5000 <= nums[i] <= 5000

  • nums 中的所有整数 互不相同

  • nums 原来是一个升序排序的数组,并进行了 1n 次旋转

思路

二分法

明显的提示,用二分


这里传统的二分可能会陷入思维陷阱,因为传统二分,用边界做基准,此时因为基准的不断变化,会导致思路难度飙升,感觉就算可以解答也会非常复杂

基准

那就找个基准


其实很容易找到,那就是数组中位置 0len(nums)-1。理论上都可以,但是这里我更推荐0


因为基准如果恰好是最小值,感觉上会增加思维的复杂度(其实并不一定,但是我本人喜欢剥离开思考问题)


0如果是最小值,恰好是一个特殊情况,恰好旋转回了原始数组,只有此种情况下:


nums[0] <= nums[len(nums)-1] 等于是只有一个元素的情况

二分思路


放个图辅助说明,二分思路其实很简单,因为除了上述特殊情况下


  • 如果 nums[mid] >= nums[0],那最小值一定在右边

  • 如果 nums[mid] < nums[0],那最小值一定在左边

特殊情况

那肯定有人会担心,如果恰好mid在最小值怎么办,上面的判断不成立了啊!不用担心,我们用外循环的一个小技巧就能覆盖住


正常来讲,二分法的外循环根据不同题目,会是 left < right 或者 left <= right,但是这道题我的思路下必须用 left <= right


因为在如图中,mid恰好在最小值的情况下,区间会走到左边


此时区间内所有数字都比nums[0]大,所以会不断累加 left,直到 left = right + 1 退出


而此时,也就恰好覆盖住了特殊的情况,找到了右边界右边的这个最小值


OK,思路基本就说完了,老样子,细节在代码注释了~

代码

func findMin(nums []int) int {    left, right := 0, len(nums)-1    // 特殊情况    if nums[left] < nums[right] {        return nums[0]    }    // 一般情况,二分查找    mid := 0    for left <= right {        mid = left + (right-left)/2        // 这里以nums[0]为基准        // 如果还用left为基准的话,因为left位置的不确定性        // 会难以判断应该往哪个方向走        if nums[mid] >= nums[0] {            left = mid + 1        } else {            right = mid - 1        }    }    // 不需要担心恰好mid在最小值的情况    // 因为那样会导致区间一直往right靠近    // 最终发现right还是大于nums[0]    // 使得 left=right+1 不满足left<=right退出    // 此时left恰好是最小值了    return nums[left]}
复制代码




欢迎关注公众号交流更多题目~


发布于: 刚刚阅读数: 4
用户头像

半亩房顶

关注

人生那么长,能写多少bug? 2018-11-16 加入

我希望,自己永远是自己。我希望,远离bug。

评论

发布
暂无评论
每日一题:LeetCode-153. 寻找旋转排序数组中的最小值_面试_半亩房顶_InfoQ写作社区