Obtain The String(序列自动机/vector+二分)

LINK

题目

在这里插入图片描述

题目大意:

给出两个字符串s和t,现有一个空字符串z
每次可以取s的任意一个子序列加到z后面
问:至少要取多少次才能让z等价于t,若无法组成输出-1

思路:

方法一:一个类似于建树的思想
序列自动机用nxt数组存入字符信息
nxt[i][j]:字符串第i位后的字母(‘a’+j)最早出现的位置
当前字符更新到当前字符在原串中从后向前最晚出现的位置(init())
查询此次在s中取的子序列到t的位置(find)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;

int nxt[N][30];string s,st;
void init(int n){
	for(int i=n;i>=1;i--){//从后往前遍历 
		for(int j=0;j<26;j++)nxt[i-1][j]=nxt[i][j];
		nxt[i-1][s[i-1]-'a']=i;
	}
}
int find(int pos){
	if(nxt[0][st[pos]-'a']==0)return -1;
	for(int i=pos,cmp=0;i<st.size();i++){
		cmp=nxt[cmp][st[i]-'a'];
		if(cmp==0)return i;
	}
	return -625;
}
signed main(){
    int t,ans;cin>>t;
    while(t--){
    	ans=0;
    	memset(nxt,0,sizeof(nxt));
    	int ans=0;
    	cin>>s>>st;
    	init(s.size());
    	int pos=0;
    	while(1){
    		ans++;
    		pos=find(pos);
    		if(pos==-1||pos==-625)break;
		}
		if(pos==-1)cout<<-1<<endl;
		else cout<<ans<<endl;
	}
	
    return 0;
}

方法二:
用数组v存入字符串s的信息
v[i][j]:字符’a’+i在s中的第j个在s中的位置
二分查找v[x]中大于pos且离pos最近的x所在的位置

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;

vector<int>v[30];
int siz[30];
signed main(){
	int t;cin>>t;string s,st;
	while(t--){
		cin>>s>>st;
	    memset(siz,0,sizeof(siz));
	    int lens=s.size(),lent=st.size();
	    for(int i=0;i<26;i++)v[i].clear();
	    for(int i=0;i<lens;i++){
	    	v[s[i]-'a'].emplace_back(i);
	    	siz[s[i]-'a']++;
		}
		int flag=0,pos=-1,ans=1;
	    for(int i=0,x,b;i<lent;i++){
	    	x=st[i]-'a';
	    	if(siz[x]==0){
	    		flag=1;break;
			}
			if(pos>=v[x][siz[x]-1]){
				ans++;
				pos=v[x][0];
			}else{
				b=upper_bound(v[x].begin(),v[x].end(),pos)-v[x].begin();
				pos=v[x][b];
			}
		}	
		if(flag){
			cout<<-1<<endl;
		}else{
			cout<<ans<<endl;
		}
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值