Description
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。 得到“答案正确”的条件是:
- 字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
- 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x或者是空字符串,或者是仅由字母 A 组成的字符串;
- 如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。 现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
Input
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。
Output
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。
Sample Input
8
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
Sample Output
YES
YES
YES
YES
NO
NO
NO
NO
参考程序:
def FullChar(string,char):
for i in string:
if i!=char:
return False
return True
n=int(input())
for k in range(n):
test=input()
CharSet=set()
StandardSet={'P','A','T'}
for i in test:
CharSet.add(i)
if CharSet==StandardSet:#可以保证字符串含且仅含P/A/T三个字符
P_index=test.index("P")
left=test[0:P_index]
if len(left)==0:
if test[0]=="P" and test[-1]=="T" and FullChar(test[1:len(test)-1],"A"):
print("YES")
else:
print("NO")
else:
if FullChar(left,"A"):
T_index=test.index("T")
right=test[T_index+1:]
if FullChar(right,"A"):
#格式为a*'A',(1+n)*'A',(c+n)*'A' 其中a=c.
middleA=T_index-P_index-1
if (middleA-1)*len(left)==len(right)-len(left):
print("YES")
else:
print("NO")
else:
print("NO")
else:
print("NO")
else:
print("NO")
分析:本题是PAT (Basic Level) 1003“ 我要通过!”。属于字符串处理的题目。这里边的难点主要在于题目的理解上,本人做这道题的时候,也懵圈了好久。下面我们来一起分析一下。从题目所述“答案正确”的三点要求入手:
- 条件1说明,此字符串必须包含P/A/T三种字符,且只能包含这三种,缺少字母种类、过多类的字母、小写字母等都是不合法的。这一点我想大家都能理解,也容易设计实现。上面的程序中,使用一个集合来处理字符串,相当于“去重”
- 条件2说明,形如 xPATx
的字符串是“答案正确的”。如果说条件1是在整体上介绍了“答案正确”字符串应具有的最基本的特征,那么条件2就是说明了“答案正确”字符串的本源所在。这里可以举出两个典型例子:PAT (对应于x为空字符),AAPATAA(对应于x为三个A构成的字符串)。请记住这两个例子,它将作为母版,其他所谓“正确字符”必然是这种字符串的变形。 - 条件3说明,将一个已判定为“答案正确”的字符串,施以某种变换得到的字符串也是正确的。这里包含两层含义:①在条件2举出的两个基本例子,进行变换后,是“答案正确的”,例如PAT
→ PAAT(a=’’,b=‘A’,c=’’),即PAAT“答案正确”。又如AAPATAA →
AAPAATAAAA(a=‘AA’,b=‘A’,c=‘AA’)。②在①的基础上再次施以该变换。也是“答案正确的”,如PAAT→
PAAAT,AAPAATAAAA→ AAPAAATAAAAAA。
因此,可以看出,对于“答案正确”的定义属于一种递推式的定义;而且无论怎么变换,任何字符串必然来自于xPATx;
所以就是,我们从xPATx入手,即可找到规律。
规律总结如下:
- ①若x为空,则PA…A(不少于一个A)T是“答案正确的”
- ②若x不为空,那么对于aPbTc,为了叙述方便,不妨把a,b,c看做A的个数,那么变换n次,P左边的式子应变成a个‘A’,也就是不论怎么变换,左边部分子串永远是不变的,这给我们提供了一个重要信息——个数a是几。中间应变成(b+n)个‘A’,且根据条件2,b最初是1.这也能给出个数a是几。右边的部分变成(c+a*n)个‘A’,且根据条件2,最初c和a是相等的。
本题程序主要基于遍历(一个个统计)。其实还可以借助正则表达式来实现,例如,使用“至少出现零次、一次”通配符,设计匹配模式:r’A*PA+TA*'可以一下子去掉形如PAPAT,APATPATA,PTA,这类的,剩下的再统计个数加以判断,代码会更加简洁。
运用了正则表达式的改进版程序如下:
import re
pat=re.compile(r'A*PA+TA*',flags=0)
n=int(input())
for k in range(n):
test=input()
if re.match(pat,test):
P_index=test.index("P")
left=test[0:P_index]
if len(left)==0:
print("YES")
else:
T_index=test.index("T")
right=test[T_index+1:]
middleA=T_index-P_index-1
if (middleA-1)*len(left)==len(right)-len(left):
print("YES")
else:
print("NO")
else:
print("NO")
注意:上述代码的匹配模式不能是r’(A*)PA+T\1’,\1表示引用第一个分组,即要求这个位置和第一个分组完全相同才ok,在这种模式下,必须要求a,c相同。事实上a,c不同也可能是“答案正确”的,比如AAPAAATAAAAAA。
下面是验证匹配模式正确性的例子。
import re
pat=re.compile(r'A*PA+TA*',flags=0)
ls=['AAAAAPAAAATAA','PAT','AAAPAT','APTA','AAPATAA']
for st in ls:
if re.match(pat,st):
print(st+"匹配成功")
else:
print(st+"匹配失败")
运行结果:
将匹配模式改为
pat=re.compile(r'(A*)PA+T\1',flags=0)
运行结果: