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

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

已知一个长度为 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], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-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];
    }
相关推荐
你撅嘴真丑4 小时前
第九章-数字三角形
算法
uesowys5 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
ValhallaCoder5 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮5 小时前
AI 视觉连载1:像素
算法
智驱力人工智能5 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
孞㐑¥6 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
月挽清风6 小时前
代码随想录第十五天
数据结构·算法·leetcode
XX風6 小时前
8.1 PFH&&FPFH
图像处理·算法
NEXT067 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
代码游侠7 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法