Skip to main content

双指针

Summary

双指针同时维护两个下标,通过同向或相向移动来维护区间信息或统计答案,省去暴力枚举的重复计算。最常见的是滑动窗口:对具单调性的区间信息,固定右端点右移,条件不满足时收缩左端点,每步 O(1)、两指针各至多移动 n 次,总复杂度 O(n)。另一类是在有序数组上相向逼近:左右指针按当前值与目标的大小关系向内靠拢。双指针也是莫队算法的基础。给出无重复字符最长子串的实现。例题为洛谷 P1102 与 P1366。

参考资料​

简介​

双指针(Two Pointers)同时维护两个下标(指针),通过同向或相向移动来维护区间信息或统计答案,避免暴力枚举的重复计算。

最常见的用法是「滑动窗口」:对具有单调性的区间信息(如正整数之积、元素之和),固定右端点 rr 向右移动,当条件不满足时收缩左端点 ll,每步操作 O(1)O(1),两指针各最多移动 nn 次,总时间复杂度 O(n)O(n)。

另一类用法是在有序数组上「相向移动」:ll 从左端出发,rr 从右端出发,根据当前值与目标的大小关系分别向内逼近,同样 O(n)O(n) 求解。

双指针也是莫队算法的基础:离线排序后,用两个指针记录当前区间,逐步扩缩转移答案。

实现​

以「无重复字符的最长子串」为例:给定字符串 ss,求不含重复字符的最长连续子串长度。

337 Bcpp
#include <bits/stdc++.h>
using namespace std;

int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s;
cin>>s;
int n=s.size(),ans=0;
int cnt[128]={};
for(int l=0,r=0;r<n;r++)
{
cnt[(int)s[r]]++;
while(cnt[(int)s[r]]>1)
{
cnt[(int)s[l]]--;
l++;
}
ans=max(ans,r-l+1);
}
cout<<ans<<'\n';
return 0;
}

例题​

给出一串正整数数列以及一个正整数 CC,要求计算出所有满足 A−B=CA-B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

给出两个数列 a,ba,b,均按不降序排序。其中保证 aa 中没有重复的数字。

现在请你求出:aa 中每一个数字在 bb 中出现了几次?