1040 有几个PAT(25)
字符串 APPAPT 中包含了两个单词 PAT,其中第一个 PAT 是第 2 位(P),第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位(P),第 4 位(A),第 6 位(T)。
现给定字符串,问一共可以形成多少个 PAT?
输入格式:
输入只有一行,包含一个字符串,长度不超过10^5 ,只包含 P、A、T 三种字母。
输出格式:
在一行中输出给定字符串中包含多少个 PAT。由于结果可能比较大,只输出对 1000000007 取余数的结果。
输入样例:
APPAPT
输出样例:
2
Solution:
先用最暴力的方法求解, 1,2AC, 后三个超时, 15分, 如何解决3sum问题?
using namespace std;
int main() {
string s; cin >> s;
int n = s.length(), cnt = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'P') {
for (int j = i+1; j < n; j++) {
if (s[j] == 'A') {
for (int k = j+1; k < n; k++) {
if (s[k] == 'T') {
cnt++;
}
}
}
}
}
}
printf("%d\n", cnt ? cnt % 1000000007 : 0);
return 0;
}
其实这道题目跟3sum问题还是有区别, 是属于观察特性, 总结规律的题目.
对于每一个A来说, 可以跟它组合个数是, 前面P的个数*后面T的个数.
给出一种新的解法。// 计算每个A左边有几个P, 右边有几个T, 相乘
using namespace std;
int main() {
string s; cin >> s;
int sum = 0, n = s.length();
for (int i = 0; i < n; i++) {
if (s[i] == 'A') {
int left_P = 0, right_T = 0;
int p = i-1, q = i+1;
while (p >= 0) {
if (s[p] == 'P') left_P++;
p--;
}
while (q < n) {
if (s[q] == 'T') right_T++;
q++;
}
sum += left_P * right_T;
}
}
printf("%d\n", sum);
return 0;
}
// case3, 4, wrong
但这个复杂度, 仍然后很高, 因为找过的p又重新找了。
我在外公家用他的麻将牌模拟了一遍, 找出一种新解法。
既然是需要左边的P, 右边的T, 如果从左往右扫描的话, 先用一次扫描记录字符串所有T的个数right_t
, 只要在下次扫描过程中, 用left_p
记录从左边到A所有P的个数, 碰到T之后, right_t
减1, 碰到A就左右相乘
坑点, 每次相加就需要取余数, 这里有点理不清楚, 但是先这样理解着吧。
// 优化递推的做法, |