3月20日ACwing每日一题

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;
}

3745. 牛的学术圈 I - AcWing题库

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;
}
相关推荐
Kalika0-036 分钟前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
代码雕刻家1 小时前
课设实验-数据结构-单链表-文教文化用品品牌
c语言·开发语言·数据结构
sp_fyf_20241 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
小字节,大梦想2 小时前
【C++】二叉搜索树
数据结构·c++
我是哈哈hh3 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
Tisfy3 小时前
LeetCode 2187.完成旅途的最少时间:二分查找
算法·leetcode·二分查找·题解·二分
Mephisto.java3 小时前
【力扣 | SQL题 | 每日四题】力扣2082, 2084, 2072, 2112, 180
sql·算法·leetcode
robin_suli3 小时前
滑动窗口->dd爱框框
算法
丶Darling.3 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5203 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法