剑指 offer 11 旋转数组中的最小数字(二分,细节详解)

1. 题目描述

2. 算法思路

本题的详细解来自于下,建议一看,由于二分法的细节实在是太多了,此处无法完全列举,只抛砖引玉,给我自己的思考和总结,详细可以去下文。

作者:jyd
链接:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/solution/mian-shi-ti-11-xuan-zhuan-shu-zu-de-zui-xiao-shu-3/
来源:力扣(LeetCode)
 

本渣的思考和总结:

  • 看到题目,就觉得肯定是二分,但是由于题目的特殊性,这个二分拥有很多让人头疼的细节,不过能够将时间复杂度从线性降到 log级,还是很棒滴。

首先先来分析,二分的使用:

  • i 指向numbers左端, j 指向numbers右端, m = ( i + j ) / 2
  • 我们比较numbers[m] 和 numbers[j];
    • 此处解释一下,为啥选择numbers[j],而不是和numbers[i]进行比较。
    • 因为,当示例只含有右排序数组,即numbers = [1,2,3,4,5]时,numbers[m] > numbers[i] 就无法进行判断,按道理来说,当numbers[m] > numbers[i] ,就应该向m的右边进行收缩,但是面对这种情况,向右收缩就会出错。
  • 当 numbers[m] > numbers[j] ,就说明,target一定在右边,因此 i = m + 1;
  • 当 numbers[m] < numbers[j] ,就说明,target一定在左边,因此 j = m ;
  • 当 numbers[m] = numbers[j] ,无法说明是在左边,还是在右边, j = j - 1
    • ​​​​​​​解释为啥判断不了,例如下面两个,得出的结果就不一致
    • 例 [1, 0, 1, 1, 1]:旋转点 x = 1 ,因此 m = 2在 右排序数组 中。
    • 例 [1, 1, 1, 0, 1]:旋转点 x = 3,因此 m = 2 在 左排序数组 中

​​​​​​​接下来对numbers[m] = numbers[j]的情况进行专门的分析:此处不做严格的算法证明,为了理解,我将讨论区里大佬讨论得到的结果粘出来,非常精辟。如下图,

3. 代码

class Solution {
    public int minArray(int[] numbers) {
        int i = 0;
        int j = numbers.length - 1;
        while(i < j){
            int m = (i + j) / 2;
            if(numbers[m] > numbers[j]){
                //说明在右边
                i = m + 1; //比numbers[j]大,所以一定不包含m
            }else if(numbers[m] < numbers[j]){
                //说明在左边,但是无法证明不包含m,因此j = m
                j = m;
            }else{
                j--;
            }   
        }
        return numbers[j]; //此时一定j = i
    }
}

4. 测试结果

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值