字符串基础解题框架
本节目标
用计数数组、相向扫描和多串同步扫描处理字符串的频次、规范化比较与公共前缀。
字符串题先要区分“比较的对象”是什么:有时只比较每个字符出现的次数,有时忽略大小写和标点后比较两端,有时要求所有字符串在同一列保持一致。识别比较对象后,状态设计会自然变得很小。
识别信号
- 题目只含小写字母,并询问两串是否由同一批字符组成,优先考虑 26 位计数数组。
- 题目要求忽略大小写、空格或标点后判断对称性,优先考虑相向扫描,而不是先复制并过滤整串。
- 题目要求多个字符串的共同开头,且不需要改变输入顺序,优先逐列同步检查。
这些模型共同避免了“枚举所有字符配对”或“反复比较整串”的平方级工作。
问题模型与核心不变量
计数数组的第 i 项表示字母 a + i 在两串中的净出现次数;遍历结束后全部为零,才是异位词。相向扫描中,左右指针始终指向尚未确认部分的下一个有效字符;每次确认一对后,已越过的内容都不再影响答案。多串同步扫描中,已扫描的每一列都在所有字符串中相同,第一次不一致的位置就是公共前缀的结束位置。
通用模板
计数:写入第一份频次,抵消第二份频次,检查是否全零
双指针:跳过无关字符,比较两端有效字符,随后同时收缩
逐列:以第一串当前列为基准,检查每一串的同一列
模板选择取决于题目的等价关系:字符多重集合、过滤后的序列,或每列一致性,不能混用。
模板变体
计数数组可扩展到 ASCII 或 Unicode 映射;但字符范围很小且固定时,数组比哈希表更直接。相向扫描可迁移到删除一次字符、比较两个规范化序列等问题。逐列扫描还可用于最长公共前缀的批量检查;若数据持续加入,则要维护当前候选前缀并不断截短。
母题序列
建议按必学顺序练习:
常见误区
- 对异位词排序后再比较,忽略了固定字母表下线性计数已经足够。
- 调用字符分类函数时直接传入可能为负的
char;C++ 应先转为unsigned char。 - 为了找公共前缀排序输入,既改变了输入,也做了不需要的
O(n log n)工作。 - 相向扫描只跳过一端的标点,或跳过后没有再次确认左右边界。
迁移方向
掌握这三种基础模型后,可把“频次相等”迁移到滑动窗口中的字符计数,把“规范化后比较”迁移到字符串清洗题,把“多串同列”迁移到字典、路径或编码序列的共同前缀问题。若题目转而要求子串位置、最长长度或模式匹配,则应结合滑动窗口、哈希或 KMP,而不是只保留基础扫描。