PAT B1040 有几个PAT (25point(s))

本文介绍了一种高效算法,用于计算给定字符串中特定子串‘PAT’的出现次数。通过预处理前后缀来减少计算复杂度,并提供了多种实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里采用了fgets函数,fgets()函数会读到有换行符的位置或者规定的数组结束,但是不同于gets()的另一点就是,fgets()会将换行符也存入数组中,上面的代码后三行就是过滤了换行符。

字符串 APPAPT 中包含了两个单词 PAT,其中第一个PAT 是第 2 位(P),第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位(P),第 4 位(A),第 6 位(T)。

现给定字符串,问一共可以形成多少个 PAT

输入格式:

输入只有一行,包含一个字符串,长度不超过10​5​​,只包含 PAT 三种字母。

输出格式:

在一行中输出给定字符串中包含多少个 PAT。由于结果可能比较大,只输出对 1000000007 取余数的结果。

输入样例:

APPAPT

输出样例:

2
  • 思路1:

  • code1:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 100010;
const int MOD = 1000000007;
char str[maxn];
int LeftP[maxn] = {0};
int ans = 0, RightT = 0;

int main(){
	gets(str);
	int len = strlen(str);
	for(int i = 0; i < len; ++i){
		if(i > 0)
			LeftP[i] = LeftP[i-1];
		if(str[i] == 'P'){
			LeftP[i]++;
		}
	}
	for(int i = len - 1; i >= 0; --i){
		if(str[i] == 'T'){
			RightT++;
		}
		else if(str[i] == 'A'){
			ans =(ans + LeftP[i] * RightT) % MOD; 
		}
	}
	printf("%d", ans);
    return 0;
} 
  • TIPS:
    当读入的字符串中有空格时,一般会采取gets()函数(遇到换行才会停止)
    gets(str)
    char str[200];
    fgets(str[i],200,stdin);
    while(str[i]!='\n') 
        i++;
    str[i]='\0'
  • 思路 1:打表
    对于每一个A来说,由他串起来的PAT个数 = 前面P的个数 * 后面T的个数
    用另一个对应字符串各位的空数组,记录到某一位置时前面的P个数
    再用另一个数组记录该位置后面的T个数
    最后遍历一边,累加出结果

  • code 1:

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int maxn = 100010;
const int MOD = 1000000007;
string s;
int preP[maxn], postT[maxn];
int main(){
	cin >> s;
	memset(preP, 0, sizeof(preP));
	memset(postT, 0, sizeof(postT));
	for(int i = 0; i < s.size(); ++i){
		if(i != 0) preP[i] = preP[i-1];
		if(s[i] == 'P')	preP[i]++;
	}
	for(int i = s.size()-1; i >= 0; --i){
		if(i != s.size()-1) postT[i] = postT[i+1];
		if(s[i] == 'T')	postT[i]++;
	}
	int ans = 0;
	for(int i = 0; i < s.size(); ++i){
		if(s[i] == 'A') ans += preP[i]*postT[i];
		ans %= MOD;	//必须放到里面,不然ans可能会溢出 
	} 
	printf("%d", ans);
	return 0;
} 
  • code 2:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 100010;
const int MOD = 1000000007;
string str;
int LeftP[maxn] = {0};
int ans = 0, RightT = 0;

int main(){
	getline(cin, str);
	int len = str.size();
	for(int i = 0; i < len; ++i){
		if(i > 0)
			LeftP[i] = LeftP[i-1];
		if(str[i] == 'P'){
			LeftP[i]++;
		}
	}
	for(int i = len - 1; i >= 0; --i){
		if(str[i] == 'T'){
			RightT++;
		}
		else if(str[i] == 'A'){
			ans =(ans + LeftP[i] * RightT) % MOD; 
		}
	}
	printf("%d", ans);
    return 0;
} 
  • T2 code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110000;
int cnt_p[maxn];
int main(){
	string s;
	cin >> s;
	for(int i = 1; i < s.size(); ++i){
		if(s[i-1] == 'P') cnt_p[i] = cnt_p[i-1] + 1;
		else cnt_p[i] = cnt_p[i-1];
	}
	long long ans = 0;
	int right_t = 0; 
	for(int i = s.size() - 2; i >= 0; --i){
		if(s[i+1] == 'T') right_t++;
		if(s[i] == 'A') ans = (ans + cnt_p[i] * right_t) % 1000000007; 
	}
	printf("%lld", ans);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值