求母串中的子序列 (预处理 状态机)

小z和Easy的字符串游戏

题目描述

小z玩腻了迷宫游戏,于是他找到了Easy,准备和Easy玩这么一个游戏

小Z准备了一个字符串S (S的长度不超过10000)

又准备了M个小的字符串(M最大不超过1000000,每个小字符串的长度不超过10)

现在小z想请教Easy老师,M个小字符串中有多少个小字符串是大字符串S的子序列?

如果Easy老师答不上来就要请客,现在Easy老师很苦恼,你能帮帮他吗?

子序列可以理解为不要求连续的子串,若还是不了解请看下面的链接中,最佳答案的回答

https://zhidao.baidu.com/question/120638124.html

 

输入

只有一组测试数据

第一行是大字符串S(S的长度不超过10000)

第二行是一个整数M,表示小字符串的个数(M最大不超过1000000)

接下来M行每行给出一个小字符串(长度不超过10)

保证没有空字符串

输出

输出只有一个整数,代表M个小字符串中是大字符串S的子序列的个数

样例输入

amrocegijgyvkgarnffb
4
i
jsj
qg
ac

样例输出

2

提示


样例解释:
对于4个小字符串
1 i
因为大字符串S里有i,所以i肯定是大字符串,答案+1
2 jsj
大字符串S中没有任何一个子序列是jsj
3 qg
大字符串S中没有任何一个子序列是qg 
4 ac
大字符串S中的第1个字符'a'和第5个字符'c'构成的子序列
正好是ac,答案+1 
4个小字符串中有2个字符串是大字符串S的子序列
所以答案为 2

 

思路:可以预处理出一个状态机来,next1[i]['c'] 为母串中i位置之后的c字符出现的位置,这样输入字串之后可以直接在next1数组中跑一边找一下看是否能够跑完字串;

例如 abcdeabcd

next[0]['a'] = 5(即0位置之后的第一个a字符出现在第五个位置);

next[0]['b'] = 6;

……(26个字母都找一边没有的话就是 -1(初值));

next[1][a] = 4(即1位置之后第一个a字符出现在的第4个位置);

……(整个母串的每个位置都找一边26个字母)

之后再用一个数组标记一下 26个字母第一次出现在母串中的位置;

代码 :

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
int next1[10005][10005];
int d[10005];
int main()
{
    int n;
    string s1;
    cin >> s1;
    memset(next1,-1,sizeof(next1));
    memset(d,-1,sizeof(d));
    for(int i = 0; i < s1.size(); i++){//标记i位置之后每个字母第一次出现的位置
        for(int j = 0; j < 26; j++){
            for(int k = i + 1; k < s1.size();k++){
                if(s1[k] == 'a' + j){
                    next1[i][j] = k;
                    break;
                }
            }
        }
    }
    for(int i = 0; i < 26; i++){//标记每个字母第一次出现在母串中的位置
        for(int j = 0; j < s1.size(); j++){
            if(s1[j] == 'a' + i){
                d[i] = j;
                break;
            }
        }
    }
    cin >> n;
    string s2;
    int ans = 0;
    while(n--){
        cin >> s2;
        int t = d[s2[0] - 'a'];//字串中的第一个字符在母串中第一次的位置
        int l = 0;
        while(l < s2.size()){
            if(t == -1) break;//字串中的字符不存在母串中 赋值为初值-1
            else{
                l++;
                t = next1[t][s2[l] - 'a'];//t代表上一个字母在母串中的位置,在t之后找下一个字母
            }
        }
        if(l >= s2.size()) ans++;
    }
    printf("%d\n",ans);
}
 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值