1040 有几个PAT (25分)
字符串 APPAPT 中包含了两个单词 PAT,其中第一个 PAT 是第 2 位§,第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位§,第 4 位(A),第 6 位(T)。
现给定字符串,问一共可以形成多少个 PAT?
输入格式:
输入只有一行,包含一个字符串,长度不超过105 ,只包含 P、A、T 三种字母。
输出格式:
在一行中输出给定字符串中包含多少个 PAT。由于结果可能比较大,只输出对 1000000007 取余数的结果。
输入样例:
APPAPT
输出样例:
2
题目分析:一开始很容易想到反复遍历3遍字符串,第一遍找到P,第二遍找到A,第三遍找到T。相当于用穷举法计算PAT总共出现的数目。但是会出现运行超时
TLE代码(运行超时)
//测试点2,3,4运行超时
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
string s; cin >> s;
long long int sum=0;
for(auto it=s.begin(); it!=s.end();it++ )
{
if(*it=='P')
for(auto it2=it; it2!=s.end();it2++ )
{
if(*it2 == 'A')
for(auto it3=it2 ;it3!=s.end();it3++ )
{
if(*it3 == 'T')
sum++;
}
}
}
cout<<sum%1000000007;
return 0;
}
超时原因分析: 核心算法for循环嵌套3次,时间复杂度=O(n3),遇到大数的输入容易出现超时的情况。应该在算法上优化,降低时间复杂度。
AC代码
#include<iostream>
#define Mod 1000000007
using namespace std;
int main()
{
string s; cin>>s;
int P=0,A=0,T=0;
int sum=0;
for(auto x:s ) if(x=='T') T++;//遍历一次字符串,计算'T'总共的数量
for(auto x:s )
{
if(x=='P') P++;//P表示'A'前'P'的数量
if(x=='T') T--;//表示'A'后面的'T'的数量。
if(x=='A') sum = ( sum + P*T ) % Mod;//注意不能写成sum+=P*T % Mod
}
cout<<sum;
return 0;
}
思路: 基本上套的是柳婼的思路。每当遇到一次A,先计算 (A前P的总和) 与 (A后T总和) 的积,将这些积累加之后再对1e9+7取余。
改良后的算法只有2次并列的for循环,时间复杂度为O(n) 远小于之前的O(n3),避免了运行超时。