数据结构习题--寻找旋转排序数组中的最小值

数据结构习题--寻找旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 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, a1, a2, ..., an-1] 旋转一次 的结果为数组 a\[n-1, a0, a1, a2, ..., an-2] 。

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

方法一:复杂度O(n)

分析

我们知道原来的数组是单调递增的,而经历过旋转之后,它具有的特点是前面一段和后面一段都是单调递增的,但是前面一段的最小值大于后面一段的最大值,而我们需要寻找的最小值,是在两段的分界点

而对于我们取第一个元素为最小值,遍历数组,当有元素比其小,就退出循环,该值就是我们需要寻找的最小值

代码

java 复制代码
public int findMin(int[] nums) {
        int min = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] < min){
                return nums[i];
            }
        }
        return min;
    }

方法二:二分查找 复杂度O(logn)

分析

我们知道原来的数组是单调递增的,而经历过旋转之后,它具有的特点是前面一段和后面一段都是单调递增的,但是前面一段的最小值大于后面一段的最大值,而我们需要寻找的最小值,是在两段的分界点

而我们设置一个low在数组最左边,设置high在数组最右边,而mid为其中间,当mid的元素小于high的元素时,我们就不需要管其右边的元素,直接令high到mid的位置,然后重新计算mid,当mid的元素不大于high的元素时,我们令low = mid + 1,

代码

java 复制代码
    public int findMin(int[] nums) {
        /**
         * high 表示右边的元素
         * low 表示左边的元素
         */
        int high = nums.length- 1;
        int low = 0;
        while (low < high){
            // 寻找中间的数,进行二分
            int mid = (high + low) / 2;
            // 当中间的数小于右边的数,更新此位置为右边
            if (nums[mid] < nums[high]){
                //如果中间值小于最大值,则最大值减小
//            疑问:为什么 high = mid;而不是 high = mid-1;
//            解答:{4,5,1,2,3},如果high=mid-1,则丢失了最小值1
                high = mid;
            }else {
                // 如果中间值大于最大值,最小值变大
                // 疑问:为什么 low = mid+1;而不是 low = mid;
//                 解答:{4,5,6,1,2,3},nums[mid]=6,low=mid+1,刚好nums[low]=1
//                 继续疑问:上边的解释太牵强了,难道没有可能low=mid+1,正好错过了最小值
//                 继续解答:不会错过!!! 如果nums[mid]是最小值的话,则其一定小于nums[high],走if,就不会走else了
                low = mid + 1;
            }
        }
        // 疑问:为什么while的条件是low<high,而不是low<=high呢
//         解答:low<high,假如最后循环到{*,10,1,*}的这种情况时,nums[low]=10,nums[high]=1,nums[mid]=10,low=mid+1,
//             直接可以跳出循环了,所以low<high,此时low指向的就是最小值的下标;
//             如果low<=high的话,low=high,还会再不必要的循环一次,此时最后一次循环的时候会发生low==high==mid,
//             则nums[mid]==nums[high],则会走一次else语句,则low=mid+1,此时low指向的是最小值的下一个下标,
//             则需要return[low-1]
        return nums[low];
    }
相关推荐
先吃饱再说10 小时前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰13 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术14 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六17 小时前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术18 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize19 小时前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考1 天前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
CSharp精选营1 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
美团技术团队1 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法