QDU 6-GZS and String-字符串匹配的思维题

Description

GZS has two strings s and t.

In each step, GZS can select arbitrary character c of s and insert any character d (d ≠ c) just after it.

GZS wants to convert s to t. But is it possible?

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case there are two strings s and t, one per line. 1 ≤ T ≤ 105 1 ≤ |s| ≤ |t| ≤ 105 All strings consist only of lowercase English letters. The size of each input file will be less than 5MB.

Output

For each test case, output “Yes” if GZS can convert s to t, otherwise output “No”.

Sample Input

4
a
b
cat
cats
do
do
apple
aapple

Sample Output

No
Yes
Yes
No

核心思想:

字符串s一定是字符串t的子序列,否则一定No。
因为选中的和增添的字符不能相同,我们要研究当增添的字符是连续且相同的怎么办?
我们将s中的字符和t中可匹配的字符中位置最靠后的匹配,然后采用如下方案

假设t匹配到位置j,令c=t[j+1],(c可能要被增添不止一次!)
第一步:将此部分需要被增添的所有字符c先插入(此步增添时,增添和选中的一定不同,因为如果它俩是相同的,那么他俩就匹配了,也就不用插入了)。
第二步:将其他字符逆序插入(此步增添时,由于有第一步的若干个字符c做前驱,也不会产生矛盾)。

这样,后面的字符在增添时都不矛盾了。现在,我们要找第一个被选中的位置,判断它和后面增添的字符是否相同就可以了!
分析增添方案是为了化简题目,我们的代码不用模拟增添的过程!!!

什么样的位置可以做第一个位置呢?
要求一:此位置之前s和t必须相同,因为第一个位置之前不能增添,否则就不能称之为第一个位置了!
要求二:此位置之后,s和t又能匹配成功,即s是t的子序列。怎么知道s是不是t的子序列呢?双指针遍历两个字符串即可。
结合以上两个要求,我们用一个for循环顺序寻找两个字符串第一个不同字符的位置(那么在此位置之前,两字符串相同)。将两字符串匹配时就逆序进行。
详见代码!

代码如下:

#include<stdio.h>
#include<string.h>
const int N=1e5+20;
char s[N],t[N];
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s%s",s,t);
		int k=0,flag=0,ls=strlen(s),lt=strlen(t);
		for(;k<ls&&s[k]==t[k];k++);//寻找s和t第一个不同的字符 
		for(int i=ls-1,j=lt-1;i>=0&&j>=i&&!flag;j--)//i指示s,j指示t 
		{
			if(i<k&&t[i]!=t[i+1]) flag=1;//判断位置i能否当作第一个被选中的位置 
			if(s[i]==t[j]) i--;//匹配成功i-- 
		}
		if(flag) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}
发布了144 篇原创文章 · 获赞 135 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Nothing_but_Fight/article/details/102315452