为什么要写mid = low + (high - low) / 2

概述

  1. 现象概述
    二分法,基本的代码如下。

    int binarySearch(int[] arr, int target) {
    	int left = 0;
    	int right = arr.length - 1;
    
    	while (left <= right) {
    		// 写法一
    		int mid = (left + right) / 2;
    		// 写法二
    		int mid = left + (right - left) / 2;
    		// 写法三
    		int mid = right - (right - left) / 2;
    
    		// 省略...
    	}
    }
    
  2. 简单分析
    如上所示,我们平时都会使用 写法一,但是我们在看到别人题解有时候会用写法二,于是我自创了写法三,但是写法三是错误的,写法一写法二才是对的。

    好奇的我决定一探究竟,之后在同事的帮助下完成了分析。

    写法一存在的问题是有溢出的可能。解释见示例1

    写法二和写法三概述如下:

    如下的等式是成立的:
    L + R 2 \frac{L + R}{2} 2L+R = L + R − L 2 \frac{R - L}{2} 2RL
    L + R 2 \frac{L + R}{2} 2L+R = R - R − L 2 \frac{R - L}{2} 2RL

    但是Java本身的/向下取整,所以,正确的式子应该是如下的。
    ⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor 2L+R = L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor 2RL
    ⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor 2L+R ≠ \not= = R - ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor 2RL,故写法三排除,此处证明见示例2。

    所以写法二 L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor 2RL为什么这种方式不会溢出呢?

    答:
    因为:(L + R - L) = R
    所以:(L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor 2RL) < R
    因为L和R本身都在Integer范围内,所以不会溢出。

附录

示例1

来看写法一存在的问题,假设arr的长度为Integer.MAX_VALUE,并且要寻找的值在右半边数组,那么向右找,left就会变为mid + 1,也就是 I n t e g e r . M a x v a l u e 2 \frac{Integer.Maxvalue}{2} 2Integer.Maxvalue + 1,接下来再向右寻找值的话,式子就会变成mid = I n t e g e r . M a x v a l u e 2 + 1 + I n t e g e r . M a x v a l u e 2 \frac{\frac{Integer.Maxvalue}{2} + 1 + Integer.Maxvalue}{2} 22Integer.Maxvalue+1+Integer.Maxvalue,这样分子会溢出。

示例2

证明:
反证法:

说明: ⌊ x ⌋ \lfloor x \rfloor x是向下取整的意思。

  1. 假设方法一和方法二相等,那么如下:

    ⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor 2L+R = L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor 2RL

    存在两种情况

    1. L和R同奇或同偶,那么L和R加减一定是偶数。
      则原式为 L + R 2 \frac{L + R}{2} 2L+R = L + R − L 2 \frac{R - L}{2} 2RL
      继续化简为,L + R = L + R,成立。

    2. L和R一奇一偶,那么L和R加减一定是奇数。
      奇数要向下取整,所以-1之后变为偶数,就去掉 ⌊ ⌋ \lfloor\rfloor 符号了。【-1是因为要向下取整,+1向上取整】

      则原式为 L + R − 1 2 \frac{L + R - 1}{2} 2L+R1 = L + R − L − 1 2 \frac{R - L - 1}{2} 2RL1
      继续化简为,L + R - 1 = L + R - 1,成立。

    所以方法一和方法二相等

  2. 假设方法一和方法三相等,那么如下:

    ⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor 2L+R = R - ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor 2RL

    存在两种情况

    1. L和R同奇或同偶,那么L和R加减一定是偶数。
      则原式为 L + R 2 \frac{L + R}{2} 2L+R = R - R − L 2 \frac{R - L}{2} 2RL
      继续化简为,L + R = L + R,成立。

    2. L和R一奇一偶,那么L和R加减一定是奇数。
      奇数要向下取整,所以-1之后变为偶数,就去掉 ⌊ ⌋ \lfloor\rfloor 符号了。【-1是因为要向下取整,+1向上取整】

      则原式为 L + R − 1 2 \frac{L + R - 1}{2} 2L+R1 = R - R − L − 1 2 \frac{R - L - 1}{2} 2RL1
      继续化简为,L + R - 1 = R + L + 1
      即,-1 = 1,不成立。

    所以方法一和方法三不相等

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值