题目描述
难度分:922
输入n(1≤n≤104)和n个字符串,每个字符串只包含大写字母,长度在[2,10]中。
将这些字符串按照某种顺序相连,得到字符串s。
问:s中最多可以有多少个连续子串是AB
?
输入样例1
3
ABCA
XBAZ
BAD
输出样例1
2
输入样例2
9
BEWPVCRWH
ZZNQYIJX
BAVREA
PA
HJMYITEOX
BCJHMRMNK
BP
QVFABZ
PRGKSPUNA
输出样例2
4
输入样例3
7
RABYBBE
JOZ
BMHQUVA
BPA
ISU
MCMABAOBHZ
SZMEHMA
输出样例3
4
算法
贪心构造
有这样一种贪心的构造方案,将所有字符串分成4类:
- 不是
B
开头,但是A
结尾; - 是
B
开头,且是A
结尾; - 是
B
开头,但不是A
结尾; - 既不是
B
开头,也不是A
结尾。
按照如下优先级连接出s串:
- 先用1类开头;
- 然后让2类首尾相连用尽(因为2类的优势就在于首尾有可能能够凑出边缘
AB
,尽量发挥这个优势); - 接下来连一个3类,又凑出一个连接处的
AB
; - 然后交替使用1和3类,直到两者用尽;
- 最后把4类全部连接上即可,反正4类不会产生额外的
AB
,原串中有多少个AB
它就能贡献多少个AB
,不可能再多了。
复杂度分析
时间复杂度
一共遍历了输入的n个字符串,每个字符串的长度在10以内,因此构造出的连接串s是O(n)规模的,这也是算法的时间复杂度。
空间复杂度
保存输入的n个字符串,空间为O(n);构造出来的答案串s为10n规模,仍然是O(n),因此算法的额外空间复杂度为O(n)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int n;
scanf("%d", &n);
vector<string> a, b, c, d;
for(int i = 0; i < n; i++) {
string word;
cin >> word;
if(word[0] == 'B') {
if(word.back() == 'A') a.push_back(word); // B开头A结尾的
else b.push_back(word); // B开头不是A结尾的
}else {
if(word.back() == 'A') c.push_back(word); // 不是B开头,但是A结尾的
else d.push_back(word); // 不是B开头,也不是A结尾的
}
}
int i = 0, j = 0, k = 0, l = 0;
string s;
while(i < a.size() || j < b.size() || k < c.size()) {
if(k < c.size()) {
s += c[k++];
}
while(i < a.size()) {
s += a[i++];
}
if(j < b.size()) {
s += b[j++];
}
}
while(l < d.size()) {
s += d[l++];
}
int ans = 0;
for(int i = 1; i < s.size(); i++) {
if(s[i - 1] == 'A' && s[i] == 'B') ans++;
}
cout << ans << endl;
return 0;
}