寻找旋转排序数组中的最小值 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)利用其因(题目的显示 | 隐式(需细心挖掘) 条件/个性特征),必得其果,不会偶然,这便是逻辑。

参考文献

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值