#5647. 双面鼓题解

双面鼓题解

一、详细思路分析

1. 题目核心理解

我们需要判断:按照给定的拍打顺序s(每个字符代表一次鼓的拍打,方向为字符对应的左/右),是否能通过为每次拍打分配「1次或2次声响」(声响方向与拍打方向一致),使得所有拍打产生的声响按顺序拼接后,恰好等于声音序列p

2. 核心判断条件(解题关键)

要满足题目要求,必须同时满足以下3个核心条件,缺一不可:

  • 条件1:字符块的顺序一致
    连续相同字符组成的一段称为一个「字符块」。例如 s=LLR 的块结构是 [L(2次拍打), R(1次拍打)]p=LLLRR 的块结构是 [L(3次声响), R(2次声响)]
    若s和p的块字符顺序不一致(比如s是RRL→块[R,R,L],p是LRR→块[L,R]),则直接判定为NO。 (简化判断:先检查第一个字符是否相同,若不同则块顺序必然不一致)

  • 条件2:块的数量一致
    若s和p的块数量不同(比如s有2个块,p有3个块),则块结构无法匹配,直接判定为NO

  • 条件3:每个对应块的长度满足约束
    设s中第i个块的长度为len_s[i](该块有多少次拍打),p中第i个块的长度为len_p[i](该块有多少次声响)。
    由于每次拍打最多产生2声、最少产生1声,因此单个块的总声响数需满足:
    len_s[i] ≤ len_p[i] ≤ 2 * len_s[i]
    (例如s的L块长度为2→声响数范围2~4;p的L块长度为3,满足约束)

3. 解题步骤拆解

  1. 读取测试用例数量t
  2. 对每组测试用例:
    • 读取拍打序列s(代码中为a)和声音序列p(代码中为b);
    • 检查第一个字符是否相同,不同则输出NO并跳过后续判断;
    • s进行块分解,统计每个块的长度,存入数组c
    • p进行块分解,统计每个块的长度,存入数组d
    • 检查块数量是否相同,不同则输出NO并跳过后续判断;
    • 遍历所有对应块,检查是否满足len_s[i] ≤ len_p[i] ≤ 2*len_s[i]
      • 若有任意一个块不满足,输出NO
      • 若所有块都满足,输出YES

二、完整代码注释

三、关键细节补充

  1. 块分解的边界处理
    循环中i遍历到a.size()-1时,a[i+1]会访问到字符串的「结束符」(空字符),因此a[i] != a[i+1]会触发n1++,导致块编号多算1次,所以需要n1--修正。

  2. 数组大小的选择
    c[200010]d[200010]的大小设置为2e5+10,是因为题目中字符串长度≤2e5,而块的数量最多等于字符串长度(极端情况:每个字符都是不同块,如LRLRLR...),因此2e5+10足够容纳所有块的长度。

  3. 时间复杂度
    每组用例的块分解是O(len(a) + len(b)),块检查是O(块数)(块数≤min(len(a), len(b))),因此总时间复杂度为O(t*(len(a)+len(b))),对于t≤10、字符串长度≤2e5的约束,完全满足时间要求。

四、总结

  1. 解题核心是匹配块结构+约束块长度:先保证s和p的块顺序、块数量一致,再检查每个块的声响数是否在合理范围。
  2. 块分解是将连续相同字符的段提取出来,是解决这类“连续字符序列匹配”问题的常用技巧。
  3. 边界处理(如块数修正、第一个字符检查)是避免错误的关键,需重点关注。