二分查找
二分法最重要的两个点:
1.
w
h
i
l
e
while
while循环中
l
l
l 和
r
r
r 的关系,到底是
l
≤
r
l \le r
l≤r 还是
l
<
r
l \lt r
l<r
2.迭代过程中
m
i
d
mid
mid 和
r
r
r 的关系,到底是
r
=
m
i
d
−
1
r = mid - 1
r=mid−1 还是
r
=
m
i
d
r = mid
r=mid
这里贴出一种写法:每次查找的区间在 [ l , r ] [l, r] [l,r](左闭右闭区间),根据查找区间的定义(左闭右闭区间),就决定了后续的代码应该怎么写才能对。因为定义 target 在 [ l , r ] [l, r] [l,r]区间,所以有如下两点:
循环条件要使用
w
h
i
l
e
(
l
≤
r
)
while(l \le r)
while(l≤r),因为当
(
l
=
r
)
(l = r)
(l=r)这种情况发生的时候,得到的结果是有意义的
i
f
(
n
u
m
s
[
m
i
d
]
>
t
a
r
g
e
t
)
if(nums[mid] \gt target)
if(nums[mid]>target) ,
r
r
r 要赋值为
m
i
d
−
1
mid - 1
mid−1, 因为当前的
n
u
m
s
[
m
i
d
]
nums[mid]
nums[mid] 一定不是
t
a
r
g
e
t
target
target ,需要把这个
m
i
d
mid
mid 位置上面的数字丢弃,那么接下来需要查找范围就是
[
l
,
m
i
d
−
1
]
[l, mid - 1]
[l,mid−1]
参考代码
int l=1,r=n;
while(l <= r){
// Prevent (l + r) overflow
//int mid = l + (r - l) / 2;
int mid=(l+r)>>1;
if(nums[mid] == target){ return mid; }
else if(nums[mid] < target) { l = mid + 1; }
else { r = mid - 1; }
}
二分答案
最大值最小化(最大值的最小值)
while(l<r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
最小值最大化(最小值的最大值)
while(l<r){
int mid=(l+r+1)>>1;//防止死循环。假设l=3,r=4,最大值为4时取到,不加1就mid就一直为3
if(check(mid))l=mid;
else r=mid-1;//防止死循环
}