双指针/滑动窗口 优化 二分区间

二分区间:

FOR(i, 1, n, 1){
	int lef = 根据i来二分;
	int rig = 根据i来二分;
}	

他的时间是: O(n * logN)。

如果说,每一次的{lef, rig},满足某种单调性
即:{lef[1], rig[1]} {lef[2], rig[2]} {lef[3], rig[3]} ..... 他们满足某种单调性

可以考虑用:双指针/滑动窗口,优化成O(n)


有n个一维的 递增的 点A, 有m个一维的 递增的 人B,有一个len距离,表示: 一个人可以覆盖 左右[-len, len]的点。

问,这些人 是否可以覆盖所有点。

动态维护一个rig,表示: 前i个人,已经覆盖了A[1, 2, 3..., rig]这些点。
当前遍历的第i+1个人,根据{ B[i+1] - m, B[i+1] + m }范围 获取[l] [r],表示:A[l, l+1, .., r]这些点 是处于这个范围的。
if( l <= rig ) MAX(rig, r);

这是二分的做法,每次二分获取一个[l, r],然后用这个区间 尝试更新rig。


B是单调的,每次得到的[l] [r],也是单调的。
因此,其实不需要二分得到[l] [r]。 直接每次尝试让rig增长即可。

bool check( int len ){
	int pre_rig = 0;
	
	FOR(i, 1, m, 1){
		LL lef = (LL)B[i] - len, rig = (LL)B[i] + len;
		
		while( pre_rig + 1 <= n ){
            if( A[pre_rig + 1] >= lef && A[pre_rig + 1] <= rig ){
                ++ pre_rig;
            }
            else{
                break;
            }
		}
		
		if( pre_rig == n )
		    return true;
		
	}
	return pre_rig == n;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值