本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目
给定一个长度为 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 ≤ 10^5,
−10^9 ≤ ai,bi ≤ 10^9
输入样例:
3 5
1 3 5
1 2 3 4 5
输出样例:
Yes
思路
因为两个数组是有序的,可以利用这个特性使用双指针算法
1.j指针用来扫描整个b数组,i指针用来扫描a数组。若发现a[i]==b[j],则让i指针后移一位。
2.整个过程中,j指针不断后移,而i指针只有当匹配成功时才后移一位,若最后若i==n,则说明匹配成功。
整个过程中j指针不断扫描b数组并且向后移动,相当于不断给i指针所指向的a数组创建匹配的机会,只有匹配成功时i指针才会向后移动一位,当i==n时,说明全部匹配成功。
时间复杂度为O(n)
ac代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
int main(){
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
for (int i = 0; i < m; i ++ ) scanf("%d", &b[i]);
int i = 0, j = 0;
while (i < n && j < m){
if (a[i] == b[j]) i ++ ;
j ++ ;
}
if (i == n) puts("Yes");
else puts("No");
return 0;
}
Java
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
int[] a = new int[n];
int[] b = new int[m];
for(int i = 0 ; i < n ; i ++ ) a[i] = scan.nextInt();
for(int i = 0 ; i < m ; i ++ ) b[i] = scan.nextInt();
int i = 0 , j = 0 ;
while(i < n && j < m ){
if(a[i] == b[j]) i ++ ;
j ++ ;
}
if(i == n) System.out.println("Yes");
else System.out.println("No");
}
}