ABC299C Dango
题意分析¶
我们定义一个 $L$ 阶的 Dango 字符串为:
- 由字符
'o'和'-'组成; - 总长度为 $L+1$;
- 除开首尾字符,连续中间 $L$ 个字符必须全部是
'o'; - 首尾字符中恰好一个是
'-',另一个是'o'。
例如:
- ✅
ooo-是 3 阶 Dango(首为o,尾为-) - ✅
-oooo是 4 阶 Dango(首为-,尾为o) - ❌
-ooo-不合法(首尾都是-) - ❌
oooo没有- - ❌
-oo-o不合法(中间不是全o)
题目要求:在一个长度为 $N$ 的字符串 $S$ 中,找到所有 子串 中最长的 Dango 字符串的阶数。如果不存在合法的 Dango,输出 -1。
解题思路¶
一、关键条件归纳¶
要构成一个 Dango:
- 必须存在一段长度 $\geq 2$ 的子串;
- 且该子串中,除首尾外为一整段连续
o; - 且首或尾为
-,另一端为o; - 简化后,Dango 的结构就变成:
o+ 若干o+-,或-+ 若干o+o
即我们只需要找到满足这种结构的子串,统计其中 o 的个数 $L$,更新最大值。
二、转化为 统计连续 o 的最大值 问题¶
我们可以从左到右扫描整个字符串,维护一个变量 cnt 表示当前连续 o 的数量,额外维护 max_cnt 表示所有合法结构中 o 的最大连续长度:
- 每次遇到
o,cnt++ - 每次遇到
-: - 若
cnt > 0,说明可以与-构成合法 Dango(o...o-)- 更新
max_cnt = max(max_cnt, cnt)
- 更新
- 然后重置
cnt = 0,准备统计下一个段
解释:只要存在一个
-紧跟在连续o后,或者o紧跟在-后形成的oo...o,我们就认为它可以构成 Dango。
三、特殊情况处理¶
- 如果整个字符串中不存在
-,则无论o连续多少个,都不能构成 Dango,输出-1 - 如果所有字符不是
o,也不可能构成合法的 Dango,输出-1 - 若存在合法结构,则答案为
max_cnt
实现步骤¶
-
遍历字符串 $S$,从左到右:
- 用
cnt统计连续o的个数; - 用布尔变量
has_dash记录是否出现过-; - 每遇到一个
-:- 若
cnt > 0,说明可以构成合法 Dango(尾为-),更新max_cnt; - 重置
cnt = 0
- 若
- 每遇到
o,cnt++
- 用
-
循环结束后:
- 因为尾部可能是
o,而之前某个字符是-,也可能构成合法 Dango(如-oooo),因此需要再一次检查并更新max_cnt
- 因为尾部可能是
-
输出结果:
- 如果没有
-或最大阶数为0,输出-1 - 否则输出
max_cnt
- 如果没有
示范代码¶
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
string s;
cin >> s;
int ans = 0, cnt = 0;
for (int i = 0; i < n;i++)
{
if (s[i] == 'o')
{
cnt++;
}
else
{
ans = max(ans, cnt);
cnt = 0; // 重置计数器,进入下一次统计
}
}
ans = max(ans, cnt); // 最后一段连续的 o 在更新一次最大值
if(ans == n) // 说明全是字符 o
{
cout << -1;
return 0;
}
if (ans > 0)
{
cout << ans ;
}
else // 说明没有字符 o
{
cout << -1 ;
}
return 0;
}
时间复杂度分析¶
- 遍历整个字符串一次即可完成统计:时间复杂度为 $O(N)$;
- 空间复杂度为 $O(1)$,只需要几个变量存状态。
总结¶
- 本题本质是字符串中模式匹配与计数问题;
- 合法 Dango 字符串的形式具有规律,可归纳为特定结构;
- 借助一趟遍历即可记录所有可能 Dango 的最大阶数;
- 边界处理(如只含
o或只含-)需特别注意。
该策略直观清晰,易于实现,也符合语法题场景的考察目标。