【双指针模板】

有时在一个序列上,二段边界会和左边界同向移动,这时可以用双指针来降低一个 log 的时间复杂度。

模板分为两种:

  1. 寻找最右 / 最左二段边界
  2. 寻找等于某数值的区间

模板一:

按边界左是 0 还是 1 分类:

  • 寻找 11110000 的最右的一个 1
  • 寻找 00001111 的最右的一个 0

按两指针是否能重合 : 1. 不可重合 2. 可重合

在实现上的细节:假设序列范围是 [1,n]

  • 如果能重合,i = 1 -> n,if(i == j) j ++ ;要放到循环最后
  • 如果不能重合,i = 1 -> n-1,为 j 腾出位置,if(i == j) j ++ ;要放到循环最前

如果不存在有效区间,要注意防止 j 的回退。

模板:

寻找最右的 1

    for(int i = 1, j = 1; i <= n;  i ++ ) // 可重合, 11110000
    {
        while(j <= n && check(i, j)) j ++ ; if(i != j) j -- ;
        if(check(i, j)) ans += j - i + 1;
        if(i == j) j ++ ;
    }

寻找最右的 0

    for(int i = 1, j = 1; i < n;  i ++ ) // 不可重合, 00001111
    {
        if(i == j) j ++ ;
        while(j <= n && check(i, j) == 0) j ++ ; if(i + 1 != j) j -- ;
        if(check(i, j)) ans += j - i + 1;
    }

同理,如果要找最左的 1 或最左的 0,不用让 j 回退即可。注意特判越界的情况,要改为 if(j == n + 1) j -- ;


如果双指针的前进方向是相向的话,模板和上面的也差不多。

举例:寻找升序区间有多少个 ( i , j ) , i < j (i,j),i < j (i,j),i<j 满足 a [ i ] + a [ j ] ≤ k a[i]+a[j]≤k a[i]+a[j]k

for(int i = 1, j = n; i + 1 <= j; i ++ ){
        while(j > i + 1 && q[i] + q[j] > k) j -- ;
        if(q[i] + q[j] <= k) res += j - i;
    }

模板二:

举例:在一个非严格递增(非严格递减同理)离散序列中,找到对应值的区间的左右端点。

举例:问一个序列中有多少个子序列满足和刚好等于 k 。

模板:固定左端点,右移两个右端点,要找到右端点的有效区间,则找到第一个 a j 1 ≥ k a_{j_1}≥k aj1k a j 2 ≥ k + 1 a_{j_2}≥k+1 aj2k+1 的区间, 即 [ j 1 , j 2 ) [j1, j2) [j1,j2) 为所求。注意要排除不存在有效区间的情况,即 j 1 > n j1 > n j1>n.

    for(int i = 1, j1 = 1, j2 = 1; i <= n; i ++ )
    {
        while(j1 <= n && query(i, j1) < k) j1 ++ ;
        while(j2 <= n && query(i, j2) <= k) j2 ++ ;
        if(j1 <= n) ans += j2 - j1;
        if(j1 == i) j1 ++ ;
        if(j2 == i) j2 ++ ;
    }

注: q u e r y ( i , j ) query(i,j) query(i,j) 表示 ∑ k = i j a k \sum_{k=i}^{j}{a_k} k=ijak
题目:小y的序列


最长连续不重复子序列AC代码
dd爱框框AC代码
Xor Sum 2AC代码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值