拼凑 牛客练习赛70

来源:牛客网:

题目描述

牛牛还是很喜欢字符串"puleyaknoi"。

牛牛有T个超长超长的字符串,不过这次他更懒了,他希望直接在字符串中看见他喜欢的字符串。

如果一个子串中含有一个子序列是”puleyaknoi“,那么他就把这个子串称作好的子串。

牛牛是个懒人,他不喜欢看太长的子串,那样他会觉着眼镜很累。

你能帮他求出对于每个字符串,最短的好的子串的长度是多少吗?

如果没有,请输出-1。

输入描述:

第一行一个T表示数据组数

接下来T行每行一个字符串(保证字符串只含小写字母)

输出描述:
共T行每行一个答案
示例1
输入
复制

3
sxpuleyaaknoip
pionkaayelupxs
yydspwuwlwewywawkwnwowiw

输出
复制

11
-1
19

备注:
T<=10,字符串长度不超过10^5T≤10,字符串长度不超过10
5

题解:

我一开始想的是在A题的基础上改,A题是打乱顺序,B题是找子串,子串其实就是相对位置已经固定,只是不一定靠着而已
我用A题作为模板改完后,意识到复杂度过高,肯定会TEL,决定换一个方式
用序列自动机来做,序列自动机专门来求子串问题,典型的空间换时间,
记录每个位置往后最近的字母的位置
然后从p才是出发匹配我们所需要的子串

int nxt[maxn][30];
int now[30];
char s[maxn];
void init()
{
    //序列自动机预处理
    memset(now, -1, sizeof now);            //mow_i表示第i个字母在原串中从后向前最晚出现的位置
    int len = strlen(s);
    --len;
    for(int i = len; ~i; --i)               //处理每一个字符
    {
        for(int j = 0; j < 26; ++j)        //找出第i个字符后面的26个字母最早出现的字符的位置
            nxt[i][j] = now[j];
        now[s[i] - 'a'] = i;                //用当前字符更新当前字符在原串中从后向前最晚出现的位置
    }
}

查找时这样
now = nxt[now][mark[pos++] - ‘a’];
从前向后找

代码:

#include<bits/stdc++.h>
const int INF=1e8+9; 
using namespace std;
string s="puleyaknoi";
const int maxn=1e5+9;
int nxt[100009][37];
int now[maxn];
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		string a;
		cin>>a;
		for (int i = 0; i < 26; i++) nxt[a.length()][i] = -1;
		for(int i=a.length()-1;i>=0;i--)
		{
			for(int j=0;j<26;j++)nxt[i][j]=nxt[i+1][j];
			
			int w=a[i]-'a';
			nxt[i][w]=i;
		} 
		int ann=INF;
		for(int i=0;i<a.length();i++){
			if(a[i]==s[0])
			{
				
				int time=nxt[i][s[0]-'a'];
				int pos=1;
				while(time!=-1&&pos<10){
					time=nxt[time][s[pos++]-'a'];
				}
				if(time!=-1&&pos==10)ann=min(ann,time-i+1);
			}
		}
		if(ann==INF)cout<<-1<<endl;
		else cout<<ann<<endl; 
	}
	return 0;
}
posted @ 2020-09-26 14:09  回归梦想  阅读(60)  评论(0编辑  收藏  举报