篮球杯 双指针专题

总的来说,双指针分为while(1)类型和尺取法类型

可以解决各种问题,前提是满足单调性(如子序列问题)

活动 - AcWing

思路:

while(1)型的双指针

注意边界问题

注意考虑是否去掉前缀和后缀,即会不会少算贡献

去掉前缀和后缀:

while(L<=N&&a[L]==0) L++;
while(R>=1&&a[R]==0) R--;

然后拿L代替1,R代替N,去做while(1)型的双指针

其基本形式为:

while(1){
        if(l>R||r>R) break;
        while(l<=R&&条件) l++;
        r=l;
        while(r<=R&&条件) r++;
        if(条件) 计算贡献
        l=r;
    }

还有一种类似的写法:

F(i,L,R){
        if(w[i]==2){
            if(!L_idx) continue;
            v.push_back(i - L_idx);
            L_idx = 0;
        }
        else{
            if(!L_idx) L_idx = i;
        }
    }

就是去枚举到所有的满足条件的区间,然后去计算贡献

799. 最长连续不重复子序列 - AcWing题库

思路:

尺取法式双指针

尺取法:详情见(65条消息) 尺取法总结_lamentropetion的博客-CSDN博客

尺取法维护区间map信息

Code:

#include <bits/stdc++.h>
#define int long long
#define y1 Y1
const int mxn=1e5+10;
const int mxe=2e5+10;
const int mod=1e9+7;
const double eps=1e-8;
using namespace std;
map<int,int> mp;
int n;
int a[mxn];
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int ans=-1e9;
    for(int l=1,r=1;l<=n;l++){
        while(r<=n&&!mp[a[r]]){
            mp[a[r]]++;
            r++;
        }
        ans=max(ans,r-1-l+1);
        mp[a[l]]--;
    }
    cout<<ans<<'\n';
}
void init(){}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int __=1;//cin>>__;
    init();
    while(__--)solve();return 0;
}

800. 数组元素的目标和 - AcWing题库

思路:

双指针枚举超时

可以先去枚举一个指针,然后另一个指针就确定了

去二分另一个指针即可

Code:

#include <bits/stdc++.h>
#define int long long
#define y1 Y1
const int mxn=1e5+10;
const int mxe=2e5+10;
const int mod=1e9+7;
const double eps=1e-8;
using namespace std;
int n,m,x;
int a[mxn],b[mxn];
void solve(){
    cin>>n>>m>>x;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<m;i++) cin>>b[i];
    int ans=0;
    vector<pair<int,int> > v;
    for(int i=0;i<n;i++){
        int pos1=lower_bound(b,b+m,x-a[i])-b;
        int pos2=upper_bound(b,b+m,x-a[i])-b;
        for(int j=pos1;j<=pos2-1;j++){
            v.push_back({i,j});
        }
    }
    for(int i=0;i<v.size();i++) cout<<v[i].first<<" "<<v[i].second<<" \n"[i==v.size()-1];
}
void init(){}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int __=1;//cin>>__;
    init();
    while(__--)solve();return 0;
}

2816. 判断子序列 - AcWing题库

思路:

双指针去check子序列

很多子序列问题都可以用双指针来解决

Code:

#include <bits/stdc++.h>
#define int long long
#define y1 Y1
const int mxn=1e5+10;
const int mxe=2e5+10;
const int mod=1e9+7;
const double eps=1e-8;
using namespace std;
int n,m;
int a[mxn],b[mxn];
void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=m;i++) cin>>b[i];
    a[n+1]=1e9,b[m+1]=-1e9;
    for(int l=1,r=1;l<=n;l++){
        while(r<=m&&b[r]!=a[l]) r++;
        if(r>m&&b[r]!=a[l]){
            cout<<"No"<<'\n';
            return;
        }
        r++;
    }
    cout<<"Yes"<<'\n';
}
void init(){}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int __=1;//cin>>__;
    init();
    while(__--)solve();return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值