本人数学不好,如有分析的不对,还请帮忙指正
本题需要求区间范围,且已经排好序。
说白了就是求左区间与右区间
对于求左区间,我写了以下代码
int l = 1, r = n;
while( l < r ){
int mid = l + r >> 1;
if( a[mid] < k ) l = mid + 1;
else r = mid;
}
对于if
里面的条件,可以得出
$a[mid] < k \Rightarrow a[l \cdots mid] < x$
该语句,将区间内小于k
的值部分地排除掉
$a[mid] \geqslant k \Rightarrow a[mid + 1 \cdots r] \geqslant x$
该语句,将区间内大于等于k
的值部分地排除掉,但保留了一个大于等于k
的值a[mid]
当循环体循环到最后一步,有下列几种情况
1. 假设该左区间存在
有:
- 当a[mid]<k
,此时已将所有小于k
的值全部排除掉,此时只剩下了一个数,便是目标值
- 当a[mid]>=k
,此时将所有大于等于k
的值排除掉了,但保留了一个mid
。此时这个mid
就是目标值k
2. 假设该左区间不存在
有:
- 当a[mid]<k
,同1,但此时剩下的是第一个大于k
的数。
- 对于极端情况,没有大于k
的数,则该值为整个数列最大的数
- 当a[mid]>=k
,同1,但此时剩下的也是第一个大于k
的数。
- 对于极端情况,没有小于k
的数,则该值为整个数列最小的数
对与右区间代码
int l = 1, r = n;
while( l < r ){
int mid = l + r + 1 >> 1;
if( a[mid] > k ) r = mid - 1;
else l = mid;
}
同理,但mid
需要+1
,为什么?
原因是:求mid
时是下取整,对于数列[1,2]
来说,mid
取得下标为0
。当此时进入了else
语句,使得左端点还是等于原来的左端点,使得程序在这里卡住,所以会超时。
解决方法:取mid
时变为上取整,即多加个1
括号内的意思是,满足条件的都排除掉?