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

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

已知一个长度为 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];
    }
相关推荐
tachibana26 分钟前
Go 语言的 Map 是否是并发安全的?
开发语言·数据结构·后端·golang·go·语言
行者全栈架构师19 分钟前
【鸿蒙心迹】冷启动从 2.8s 优化到 0.9s——耗时拆解与数据对比实战(HarmonyOS 7.x)
前端·算法·架构
LXY_BUAA22 分钟前
《嵌入式操作系统》_framebuffer驱动_20261008
linux·运维·算法
Logic10125 分钟前
C语言/数据结构字符串题解:统计“chhc“子串权值总和——一次遍历模式匹配
c语言·数据结构·算法·字符串·时间复杂度·空间复杂度·ascii
java_nnnn25 分钟前
LeetCode刷题滑动窗口(最大连续1的个数三+将x减到0的最小操作数)Java
算法·leetcode·职场和发展
bnmoel1 小时前
C++ 基础入门篇(六)类和对象-第三篇:运算符重载
开发语言·c++·算法·语法·运算符重载
wuyk5551 小时前
28 搜索引擎索引更新:从 LSM Tree 到布隆过滤器的高效实现
stm32·单片机·嵌入式硬件·算法
我命由我123451 小时前
LRU 缓存淘汰策略
数据结构·redis·学习·mysql·算法·缓存·学习方法
垆边人似月.1 小时前
华为题:合并区间
数据结构·c++·算法
垆边人似月.2 小时前
华为题:滑动窗口最大值
数据结构·c++·算法