• 寻找旋转排序数组中的最小值 II[经典抽象二分 + 如何破局左中右三者相等]


    前言

    这个题是我做过非常经典的抽象二分,不仅判定规则被抽象,而且还会出现判定规则“失灵”现象。
    如何破局?且需挖掘给定数组的特征,利用个性,顺势而为(正向/逆向思维),破掉难题,这便是逻辑,有因必有果,利用其因必得其果,不是偶然。

    一、寻找旋转排序数组中的最小值 II

    在这里插入图片描述

    二、经典抽象二分

    package everyday.medium;
    
    public class FindMin {
        /*
        target:寻找最小值,直接抽象二分,但是注意前 中 尾三者相等的情况。
        将旋转和未旋转的子数组分为两个子数组看。
    
        如何抽象?让nums[mid] 和 nums[0] 比较,若大于nums[0] 则mid必在第一个子数组;如果小于nums[0],那mid一定在第二个子数组中。
        特殊情况:当nums[mid] = nums[0]时,则看nums[mid] 和 nums[high]的关系,若 不等则必是nums[mid] > nums[high],那mid一定在第一个子数组中。
        那若是nums[mid] 也等于 nums[high]呐?如下,
        [2,2,2,2,2,2,2,0,1,2] | [2,2,2,0,1,2,2,2,2,2,2]
              如何破局?注意这两个子数组的个性问题,都是递增的;最大值和最小值挨着,也是唯一一对数,它俩不是递增。
              当左中右相等时,则不急着取mid,可low往前靠一步,破掉这种三者相等的情况。
              若low位就是最大位怎么办?这时可不能low++! 看nums[low] 是否大于nums[low + 1],若是,nums[low]必是数组的最大值,最小值就紧跟其后,直接返回。
    
              为什么不high--来破局?因为如果high已经在最大位上,high是不能动的。为什么不能像low 和 low + 1来判断,因为两个子数组都是递增。唯一一对非递增还是从前面过来才能碰到的。
    
         */
        public int findMin(int[] nums) {
            // 二分寻最大值,最小值会紧跟其后,抽象二分。
            int low = 0, high = nums.length - 1;
            // 二分快速找到比nums[0]小的,第一个小的。
            int first = nums[0];
            while (low < high) {
                int mid = low + (high - low + 1 >>> 1);//这里+1很重要,需要去上整,配合下面的low = mid防止死循环。
                int midVal = nums[mid];
    
                if (midVal > first) low = mid;
                else if (midVal < first) high = mid - 1;
                    // 破局的关键代码。
                else if (midVal == nums[high]) {
                    // 三个重要案例
                    // [3,3,1,3]  [3,1,3,3]  [2,2,2,0,2,2]
                    if (nums[low] <= nums[low + 1]) low++;
                        // 最大值和最小值挨着,也是唯一一对数,它俩不是递增。
                    else return nums[low + 1];
                }
                // 可合并。
                else low = mid;
            }
            return high + 1 == nums.length ? nums[0] : nums[high + 1];
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    总结

    1)经典抽象二分练习。
    2)利用其因(题目的显示 | 隐式(需细心挖掘) 条件/个性特征),必得其果,不会偶然,这便是逻辑。

    参考文献

    [1] LeetCode 寻找旋转排序数组中的最小值 II

  • 相关阅读:
    统计学习---第二章 感知机
    操作系统对内存的管理:分配与回收,虚拟内存,内存容量的扩充,内存保护,补充(程序相关:链接方式、装入方式)
    【Python】绘制 对数函数
    Vision-Dialog Navigation和Vision-and-Language Navigation简单总结
    系统学习Python——类(class)代码的编写基础与实例:类可以截获Python运算符
    剑指 Offer 11. 旋转数组的最小数字
    笔试强训(四十)
    RedisTemplate 使用 pipeline 时需要注意的问题
    2.2.3.1vim + ctags + cscope + taglist
    六、Spring Boot 整合 NoSQL(1)
  • 原文地址:https://blog.csdn.net/qq_43164662/article/details/125475728