题目描述:
字符串APPAPT中包含了两个单词“PAT”,其中第一个PAT是第2位(P),第4位(A),第6位(T);第二个PAT是第3位(P),第4位(A),第6位(T)。
现给定字符串,问一共可以形成多少个PAT?
输入格式:
输入只有一行,包含一个字符串,长度不超过105,只包含P、A、T三种字母。
输出格式:
在一行中输出给定字符串中包含多少个PAT。由于结果可能比较大,只输出对1000000007取余数的结果。
输入样例:APPAPT输出样例:
2
题目分析:
我会在下面介绍三种方法,其实这道题做之前需要进行思考,直接暴力解题的话必然超时。必须用巧方法。我们以A作为中心来看,每一个出现的A能组成PAT的个数就等于左边出现的P的个数乘以右边出现的T的个数。然后所有的A组成的PAT的个数相加就是最后的结果了。而最关键的就是该用最短的时间实现这种想法。最粗暴的方式不就写了。下面先写第一种方法,但是这个方法仍然不够快。
1.设定一个数组leftnumP[i]来记录第i个位置前有多少个P,如果当前位置的字母是P,那么leftnumP[i]=leftnumP[i-1]+1,如果不是leftnumP[i]=leftnumP[i-1].同样的方法来处理T,但是在处理的过程中遇到A,则将这个A对应的PAT个数求出来。请看代码:
#include<stdio.h>
#include<string.h>
const int maxn=100000;
const int mod=1000000007; //用于取模的常数
int leftnumP[maxn]={0},ans=0,rightnumT=0; //rightnumT用统计T出现的次数
char str[maxn];
int main()
{
gets(str); //读入字符串
for(int i=0;i<strlen(str);i++){
if(i>0){
leftnumP[i]=leftnumP[i-1]; //先从前一位置继承过来
}
if(str[i]=='P'){ //如果该位置是P,那么在此基础上在加一
leftnumP[i]++;
}
}
for(int i=strlen(str)-1;i>=0;i--){
if(str[i]=='T'){ //从后遍历字符串,如果是T则rightnumT加一
rightnumT++;
}
else if(str[i]=='A'){ //遇到一个A,立马将它对应的PAT数目求出并加入到最终的答案
ans=(ans+leftnumP[i]*rightnumT)%mod;
}
}
printf("%d",ans); //输出
return 0;
}
使用这种方法仍不够快,最后提交时仍然会有测试点超时。
2.使用数组,在进行读取数组的内容是仍会耗费时间,下面不使用数组。并且改用读取元素更快的string代替字符数组
#include<iostream>
#include<string.h>
using namespace std;
const int maxn=100000;
const int mod=1000000007;
int leftnumP=0,ans=0,rightnumT=0; //用于统计P的leftnumP,最终的答案ans,统计T的rightnumT
string str; //使用string,要比字符数组的计算速度更快
int main()
{
cin>>str; //读入字符串
for(int i=0;i<str.length();i++){
if(str[i]=='P'){
leftnumP++; //遍历统计所有的P出现的次数。
}
}
for(int i=str.length() -1;i>=0;i--){ //从后开始重新遍历字符串
if(str[i]=='T'){
rightnumT++; //遇见T,计数器加一
}
if(str[i]=='P'){ //遇见P,则该位置左边的字符串中P的个数又少了一个。计数器减一
leftnumP--;
}
if(str[i]=='A'){ //一旦遇见A,此时的rightnumT正是这个A右边T的个数,liftnumP是这个A左边P的个数
ans=(ans+leftnumP*rightnumT)%mod; //计算这个A对应的所有PAT的个数并计入到最终结果中
}
}
printf("%d",ans); //输出
return 0;
}
使用这种方法更快,能通过所有的测试点。
3.这种方法更加快捷和简单,运行速度要提高一倍。我们不妨将目光放在T上,每个T能形成PAT的数目要看其之前能有多少个PA,而这些PA的数量又是每个A对应形成的PA的求和,每个A能形成多少PA由这个A之前有多少个P决定。所以请看下面的代码:
#include<stdio.h>
#include<string.h>
const int maxn=100000;
const int mod=1000000007; //用于取模的常数
int main()
{
int Pnum=0,PAnum=0,PATnum=0;
char letter;
while(1){
letter=getchar();
if(letter=='\n'){ //如果读到换行符,则终止循环。
break;
}
if(letter=='P'){
Pnum++; //出现P的次数
}
if(letter=='A'){
PAnum=(PAnum+Pnum)%mod; //这个A能形成的PA的数目是它之前的P出现的次数,并将它加入到对所有PA的汇总中
}
if(letter=='T'){
PATnum=(PATnum+PAnum)%mod;
}
}
printf("%d",PATnum); //输出
return 0;
}
我突然发现使用while循环和getchar()结合,可以快速的处理字符串问题。哈哈哈哈。