cpp
//双指针模板
for(int i = 1 , j = 1; i <= n ; i ++){
while(j < i && check(i , j ) ) j ++;//check是不符合条件
// 需要处理的逻辑
}
双指针算法分为两种类型:指向两个序列,指向一个序列。
双指针算法的核心思想 就是利用了某些单调性质 把原来通过 i, j 两重循环的O(n2)优化到O(n)。
下面举一个简单的例子:
例
给一个单词字符串序列,每一个单词之间用一个空格分隔,请将每一个单词一行的格式将单词输出。
输入格式
adc def ghi
输出格式
abc
def
ghi
cpp
#include <iostream>
using namespace std;
const int N = 1e3 + 10;
char str[N];
int main()
{
gets(str);
for (int i = 0; str[i]; i++)
{
int j = i;
while (str[j] && str[j] != ' ') j++;
// 这道题的逻辑
for (int k = i; k < j; k++) cout << str[k];
cout << endl;
i = j;
}
return 0;
}
本题的思路
双指针算法一般都是先想一个朴素做法:
cpp
// 朴素做法O(n2)
for (int i = 0; i < n; i++)
for (int j = 0; j < i; j++)
if (check(j, i)) res = max(res, i - j + 1);
一、题目描述
给 定 一 个 长 度 为 n 的 整 数 序 列 , 请 找 出 最 长 的 不 包 含 重 复 的 数 的 连 续 区 间 , 输 出 它 的 长 度 。 给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。给定一个长度为n的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
输入格式
第 一 行 包 含 整 数 n 。 第一行包含整数 n。第一行包含整数n。
第 二 行 包 含 n 个 整 数 ( 均 在 0 ∼ 1 0 5 范 围 内 ) , 表 示 整 数 序 列 。 第二行包含 n 个整数(均在 0∼10^5 范围内),表示整数序列。第二行包含n个整数(均在0∼10
5
范围内),表示整数序列。
输出格式
共 一 行 , 包 含 一 个 整 数 , 表 示 最 长 的 不 包 含 重 复 的 数 的 连 续 区 间 的 长 度 。 共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。
数据范围
1 ≤ n ≤ 1 0 5 1≤n≤10^51≤n≤10
5
输入样例:
5
1 2 2 3 5
1
2
输出样例:
3
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_46680603/article/details/119207515
cpp
//朴素写法
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;//二维数组不能完全输入的时候要检查一下是不是数组开的太大
int a[N];
bool sp[N];
void solve(){
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int len=0;
for(int i=1;i<=n;i++){//快指针
len=1;
memset(sp,0,sizeof sp);//记得初始化
sp[a[i]]=1;
for(int j=i-1;j>=1;j--){//慢指针 想想为什么要从i-1开始 不然直接跳
if(!sp[a[j]]){
len=max(len,i-j+1);
sp[a[j]]=1;
}else break;
}
}
cout<<len;
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
while(t--)solve();
return 0;
}
cpp
//双指针写法
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], cnt[N], n;
int main(){
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
int res= 0;
for (int i = 1, j = 1; i <= n; i++){//右指针i 左指针j
cnt[a[i]]++; //初始化
//如果区间长度合法 但是不符合条件
while (j < i && cnt[a[i]] > 1) cnt[a[j++]]--;//左指针右移且删去相应的数
res = max(res, i - j + 1);//每次更新长度
}
printf("%d\n", res);
return 0;
}
cpp
//写法1:二分
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;//二维数组不能完全输入的时候要检查一下是不是数组开的太大
int a[N], bulk[N];
int n,l;
bool check(int mid){//最大的h指数为mid
int temp=lower_bound(a+1,a+n+1,mid)-a;//mid第一次出现的位置
int len= n-temp+1;//出现的次数
if(len>=mid)return true;
//如果本来不够 但是用技能之后够了也行
if(len+min(bulk[mid-1],l)>=mid)return true;
return false;
}
void solve(){
cin>>n>>l;
for(int i=1;i<=n;i++){
cin>>a[i];
bulk[a[i]]++;//表示某个引用次数的文献有多少个
}
sort(a+1,a+n+1);
int l=0,r=n+1;
while(l<r){
int mid=l+r+1>>1;
if(check(mid))l=mid;
else r=mid-1;
}
cout<<l;
}
signed main() {ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
while(t--)solve();
return 0;
}
cpp
//写法2:双指针
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
signed main() {
int n, l;
cin >> n >> l;
int bulk[N]; // 存取每个数的个数
int mx = 0;
for(int i = 1; i <= n; i ++ ) {
int a;cin >> a;
bulk[a] ++ ;
mx = max(mx, a); // 记录最大值
}
int res = 0; // 最终结果
int sum = n; // 初始化,目前大于0的个数肯定是所有数量
//i表示引用次数,bulk[i]表示引用次数为i的数量
//j表示h指数
for(int i = 0,j = 0; i <= mx + 5; i ++ ) { // ma + 5 开大保险(展示容错),未处理k
while(sum >= j && i >= j) { // 双指针的重点,个数要比j多,i要比j大
res = max(res, j); // 成立,h指数可以为j
j ++ ;//答案h指数就可以++
}
sum -= bulk[i]; // 总数减去引用次数为i的文章个数
if(sum + min(bulk[j-1], l) >= j ) res = max(res, j);
}
cout << res << '\n';
}
一、题目描述
给定两个升序排序的有序数组 A AA 和 B BB,以及一个目标值 x xx。
数组下标从 0 00 开始。
请你求出满足 A [ i ] + B [ j ] = x A[i]+B[j]=xA[i]+B[j]=x 的数对 ( i , j ) (i,j)(i,j)。
数据保证有唯一解。
输入格式
第一行包含三个整数 n , m , x n,m,xn,m,x,分别表示 A 的长度,B 的长度以及目标值 x。
第二行包含 n nn 个整数,表示数组 A。
第三行包含 m mm 个整数,表示数组 B。
输出格式
共一行,包含两个整数 i ii 和 j jj。
数据范围
数组长度不超过 1 0 5 10^510
5
。
同一数组内元素各不相同。
1 ≤ 1≤1≤ 数组元素 ≤ 1 0 9 ≤10^9≤10
9
输入样例:
4 5 6
1 2 4 7
3 4 6 8 9
1
2
3
输出样例:
1 1
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_46680603/article/details/119215991
cpp
//暴力写法
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;//二维数组不能完全输入的时候要检查一下是不是数组开的太大
int a[N],b[N];
void solve(){
int n,m,x;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 cnt=0;
vector<pair<int,int> >v;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i]+b[j]==x)v.push_back({i,j});
}
}
那么我们看看能否找打单调性的规律,来用双指针优化。
对于 a 数组每一个 i ,都在 b 数组中找到最小的 j,使得 a [ i ] + b [ j ] > x 时当 i 往后移动的时候 j 一定是往前移动的。
for(int i=0;i<v.size();i++)cout<<v[i].first<<' '<<v[i].second;
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
while(t--)solve();
return 0;
}
cpp
//想的时候前后都要想想 1.快慢指针类型 2.对撞类型
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;//二维数组不能完全输入的时候要检查一下是不是数组开的太大
int a[N],b[N];
void solve(){
int n,m,x;cin>>n>>m>>x;
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<m;i++)cin>>b[i];
for (int i = 0, j = m - 1; i < n&&j>=0; i++){
// 因为保证了一定有解
while (a[i] + b[j] > x&&j>0) j--;
if (a[i] + b[j] == x)
{
printf("%d %d\n", i, j);
break;
}
}
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
while(t--)solve();
return 0;
}
题目
给定一个长度为 n 的整数序列 a1,a2,...,an 以及一个长度为 m 的整数序列 b1,b2,...,bm。
请你判断 a 序列是否为 b 序列的子序列。
子序列指序列的一部分项按原有次序排列而得的序列,例如序列 {a1,a3,a5} 是序列 {a1,a2,a3,a4,a5}的一个子序列。
输入格式
第一行包含两个整数 n,m。
第二行包含 nn 个整数,表示 a1,a2,...,an。
第三行包含 mm 个整数,表示 b1,b2,...,bm。
输出格式
如果 a 序列是 b 序列的子序列,输出一行 Yes。
否则,输出 No。
数据范围
1≤n≤m≤105,
−109≤ai,bi≤109
输入样例:
3 5
1 3 5
1 2 3 4 5
输出样例:
Yes
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/falldeep/article/details/118124589
cpp
//暴力
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;//二维数组不能完全输入的时候要检查一下是不是数组开的太大
int a[N],b[N];
void solve(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>b[i];
int l=1;
for(int i=1;i<=m;i++){
if(b[i]==a[l])l++;
}
cout<<(l==n+1?"Yes":"No");
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
while(t--)solve();
return 0;
}
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;//二维数组不能完全输入的时候要检查一下是不是数组开的太大
int a[N],b[N];
void solve(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>b[i];
int l=1,r=1;
while(l<=n&&r<=m){
if(a[l]==b[r])l++;
r++;
}
if(l==n+1)cout<<"Yes";//记得这里是n+1 ,因为n时候还再循环里
else cout<<"No";
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
while(t--)solve();
return 0;
}