AcWing 2816. 判断子序列

155 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

给定一个长度为 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");
    }
}