概述
-
现象概述
二分法,基本的代码如下。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; // 省略... } }
-
简单分析
如上所示,我们平时都会使用写法一
,但是我们在看到别人题解有时候会用写法二
,于是我自创了写法三
,但是写法三
是错误的,写法一
和写法二
才是对的。好奇的我决定一探究竟,之后在同事的帮助下完成了分析。
写法一存在的问题是有溢出的可能。解释见
示例1
。写法二和写法三概述如下:
如下的等式是成立的:
L + R 2 \frac{L + R}{2} 2L+R = L + R − L 2 \frac{R - L}{2} 2R−L
L + R 2 \frac{L + R}{2} 2L+R = R - R − L 2 \frac{R - L}{2} 2R−L但是
Java
本身的/
是向下取整
,所以,正确的式子应该是如下的。
⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor ⌊2L+R⌋ = L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor ⌊2R−L⌋
但 ⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor ⌊2L+R⌋ ≠ \not= = R - ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor ⌊2R−L⌋,故写法三排除,此处证明见示例2。所以写法二 L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor ⌊2R−L⌋为什么这种方式不会溢出呢?
答:
因为:(L + R - L) = R
所以:(L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor ⌊2R−L⌋) < 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⌋是向下取整的意思。
-
假设方法一和方法二相等,那么如下:
⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor ⌊2L+R⌋ = L + ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor ⌊2R−L⌋
存在两种情况
-
L和R同奇或同偶,那么L和R加减一定是偶数。
则原式为 L + R 2 \frac{L + R}{2} 2L+R = L + R − L 2 \frac{R - L}{2} 2R−L
继续化简为,L + R = L + R,成立。 -
L和R一奇一偶,那么L和R加减一定是奇数。
奇数要向下取整,所以-1之后变为偶数,就去掉 ⌊ ⌋ \lfloor\rfloor ⌊⌋符号了。【-1是因为要向下取整,+1向上取整】则原式为 L + R − 1 2 \frac{L + R - 1}{2} 2L+R−1 = L + R − L − 1 2 \frac{R - L - 1}{2} 2R−L−1
继续化简为,L + R - 1 = L + R - 1,成立。
所以方法一和方法二相等
-
-
假设方法一和方法三相等,那么如下:
⌊ L + R 2 ⌋ \lfloor \frac{L + R}{2} \rfloor ⌊2L+R⌋ = R - ⌊ R − L 2 ⌋ \lfloor \frac{R - L}{2} \rfloor ⌊2R−L⌋
存在两种情况
-
L和R同奇或同偶,那么L和R加减一定是偶数。
则原式为 L + R 2 \frac{L + R}{2} 2L+R = R - R − L 2 \frac{R - L}{2} 2R−L
继续化简为,L + R = L + R,成立。 -
L和R一奇一偶,那么L和R加减一定是奇数。
奇数要向下取整,所以-1之后变为偶数,就去掉 ⌊ ⌋ \lfloor\rfloor ⌊⌋符号了。【-1是因为要向下取整,+1向上取整】则原式为 L + R − 1 2 \frac{L + R - 1}{2} 2L+R−1 = R - R − L − 1 2 \frac{R - L - 1}{2} 2R−L−1
继续化简为,L + R - 1 = R + L + 1
即,-1 = 1,不成立。
所以方法一和方法三不相等
-