食用指南:
对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目侧重题目分析,代码实现,以及必要的代码理解误区
题目描述:
-
给定一个长度为 n 的整数序列 a1,a2,…,an 以及一个长度为 m 的整数序列 b1,b2,…,bm。
请你判断 a 序列是否为 b 序列的子序列。
子序列指序列的一部分项按原有次序排列而 得的序列,例如序列 {a1,a3,a5} 是序列 {a1,a2,a3,a4,a5} 的一个子序列。
输入格式
第一行包含两个整数 n,m。第二行包含 n 个整数,表示 a1,a2,…,an。
第三行包含 m 个整数,表示 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 -
题目来源:https://www.acwing.com/problem/content/2818/
题目分析:
- 涉及匹配串a和被匹配串b - 双串双指针
- 暴力:
这题暴力都没有思路,很容易想到这个是双指针 - 双串双指针:
一个指针指向a串,一个指针指向b串
由于不要求连续匹配,所以即使b串中间断开,可以继续向后匹配
向下看
算法原理:
模板算法:
- 传送门:双指针是啥
本题特殊点:
-
a串一个数去和b串一个数比较,只有两个结果:
a[i] == b[j] -> i++, j++;
a[i] != b[j] -> j++;即不论是否匹配成功,j都++;
仅仅匹配成功时,i++; -
最后需要检查a串是否所有元素都在b串中被按顺序找到:
匹配完成时:i == n,其实i还有一个作用就是记录匹配成功的数目
匹配未完成时:i < n
代码实现:
#include <iostream>
using namespace std;
const int N = 100010;
int arr[N];
int brr[N];
int main(){
int n=0, m=0;
cin >>n >>m;
for(int i=0; i<n; i++) cin >>arr[i];
for(int j=0; j<m; j++) cin >>brr[j];
int i = 0, j = 0;
while(i < n && j < m){
if (arr[i] == brr[j]) i++;
j++;
}
if (i == n) cout<< "Yes"<<endl;
else cout <<"No" <<endl;
}
代码误区:
1. 匹配停止条件:
- 当a串或b串被匹配完时,匹配停止
- 当仅仅写作b串被匹配完时,留下a[n-1]可能继续和b[j]匹配成功,i可能++的大于n
2. 双指针移动情况:
- 法一写成:if(arr[i]==brr[j]) i++,j++;else j++;
- 法二写成:if(arr[i]==brr[j]) i++; j++;
- 不能写成:if(arr[i] == brr[j]) i++,j++; j++;
本篇感想:
- 非连续字符串匹配是KMP算法的爷爷
- 连续字符串匹配的双指针做法是KMP的爸爸
- 看完本篇博客,恭喜已登《练气境-初期》
距离登仙境不远了,加油