字符串 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是既处在P之后,又处在T之前,记录下这几个A的位置,用数组aa来记录,当aa等于1时,代表该位是A,利用两个long long 型变量countT与countP,countT用于统计每一个A之后的T的个数,对应的countP统计的A之前的P的个数,但这会反复遍历数组导致超时。
下面是第一次的代码,有多个超时的测试点未过:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a;
cin>>a;
int l=a.length();
int flag=0;
int aa[100000]={0};//aa用于访问字符为A的下标,相当于是一个索引表,用于确定字符的下标i
long long int countP=0,countA=0,countT=0;
for(int i=0;i<l;i++)
{
if(a[i]=='P')
{
flag=1;
}
if(flag==1)
{
if(a[i]=='A')
{
aa[i]=1;
countA++;
}
}
}//此处为了统计A的数目并且确定了在P之后的A的坐标
long long int sum=0;
for(int i=0;i<l;i++)
{
if(aa[i]==0)
{
continue;
}
else if(aa[i]==1)
{
countP=0;
countT=0;
for(int j=i;j>=0;j--)
{
if(a[j]=='P')
{
countP++;
}
}
for(int k=i;k<l;k++)
{
if(a[k]=='T')
{
countT++;
}
}
sum+=countP*countT;
}
}
cout<<sum%1000000007<<endl;
return 0;
}
//有几个PAT,给定一个字符串,求出字符串中的PAT字符数目
//尝试解题思路为,将字符A的位置确定,对每一个A(此时既有P又有T)
//对于此处P与T的数目作统计以及乘法运算,再乘上A的数目(符合条件的A)
//如何确定合适条件的A,定义一个变量为flag,当P出现时改变为1
既然多次循环超时,能不能通过一个for循环将正确的结果得出呢?参考了https://www.cnblogs.com/asinlzm/p/4440603.html此处的博文之后,稍微有了些思路。先得知道有几个在A后的T,再必须知道有几个在P后的AT,最后知道有几个P,综合以上可以得出PAT的数目。而如何方便地进行统计呢,首先按照博文的思路,将输入的字符串进行逆置,方便统计。
先利用一个Num数组存储相关的数目,即确定在T的位置存储字符T的数目,在A的位置存储合法的AT的数目,在P的位置存储合法的PAT的数目。何谓合法的,在逆序序列中,字符A必须在字符T之后出现,不然countAT便不会增加,同理,在字符A之前出现的字符P也是不合法的。判断A字符合法的标志为flagA,而P对应的是flagAT两者初始化为0。对于Num数组,一开始用于检验字符对应值的准确性,但其实这是不需要的。对于逆置字符串‘TTAAPP’而言,对应的num数组应该是‘1 2 2 4 4 8’,即T的数目为1 2 ,AT的数目为2 4(有两个AT和有4个AT),PAT的数目为(4,8)即8个PAT。不难观察得,填上数组的方式为相加,即初始化countAT为0,当出现了两个T后,countT增加至2,将flagT赋值为1。而当出现A并且合法时第一个A时AT的数目为countT,第二个A出现时,AT的数目应该再加上countT,将flagAT赋值为1.对于出现的P,作出同样的处理方法,出现一个P,在countPAT变量上添加上一个countAT。
希望之后碰见类似的字符或搭配统计题目可以想到字符逆置以及建立一个对应的哈希表,将每个字符出现时对应的信息都可以正确的反应到表上帮助思考。先分析出对应的题意,既然是排列问题,即按照规模来由小到大寻找。先找出T的数目,再找对应AT,最后是对应PAT。
代码如下:
#include <iostream>
#include <string.h>
using namespace std;
char a[100000];
char a_1[100000];
int num[100000];
int main()
{
std::ios_base::sync_with_stdio(false);
std::cin.tie(0);
num[100000]={0};
cin>>a;
int l=strlen(a);
for(int i=0;i<l;i++)
{
a_1[i]=a[l-1-i];
} //逆置
long long int countT=0,countAT=0,countPAT=0;
int flagT=0;//用于判断A前是否有T,有T countAT可加
int flagAT=0;//用于判断P前是否存在AT countPAT可加
int numA=0,numP=0;
for(int i=0;i<l;i++)
{
if(a_1[i]=='T')
{
countT++;
num[i]=countT;
flagT=1;
}
if(a_1[i]=='A'&&flagT==1)//出现A并且A合法
{
countAT+=countT;
num[i]=countAT;
flagAT=1;
}
if(a_1[i]=='P'&&flagAT==1)//出现P并且P合法
{
countPAT+=countAT;
num[i]=countPAT;
}
}
cout<<countPAT%1000000007<<endl;
return 0;
}