消除次序与最短剩余串
给定一个字符串,允许反复执行一种操作:选中一段连续相同的字符(长度不小于 2)删除;删除后左右邻居贴合,可能形成新的连续段,从而继续删除。问题是通过安排消除次序,使最终结果串最短。
次序会改变结果。abbbbccccbd 若从左先删 bbbb,中间落单的 b 再也凑不齐连续段,只能停在 abd;若先清掉隔在中间的 cccc,两侧的 b 就能合并成一段整体删去,可达更短的 ad。本页三节:操作与级联 →
固定次序贪心的失效 → 区间 DP 求最短。
1 · 操作与级联
1.1 · 操作的定义
一次消除操作在当前串中选定一段连续且相同的字符,长度不小于 2,将选定的这一段删除。所选段不必是当前串里的极长段:bbbb 里只删其中两个 b 同样合法。删除与字符个数的奇偶无关,bbbbb
这样的五连段也是一次删空。删除后被删段左右两侧的字符在新串中相邻,若它们恰好相同就构成新的连续段,可以继续被删除。这种连锁称为级联。
放宽到子段是否会得到更短的结果,这一点值得单独验证。穷举 2 字母长 9、3 字母长 8、4 字母长 7 三组共 23457 个串,「可删任意长度不小于 2 的同字符子段」与「只允许整段删极长段」两种模型给出的最短长度完全一致,差异样本为零。本页未找到这个等价性的证明,只有这份穷举证据;core/elim.ts 的实现按前者写。
1.2 · 障碍段与跨越式合并
abbbbccccbd 的位置 1–4 是 bbbb,位置 9 是一个落单的 b,中间隔着 cccc(位置 5–8)。单独看,位置 9 的 b 没有相邻同字符,消不掉。但把中间的 cccc 清空后,位置 4 与位置 9 的两个 b 在新串中相邻,五个 b 连成一段整体删除,只剩位置 0 的 a 与位置 10 的 d,即
ad。级联的价值就在于让原本被障碍段隔开的同字符跨越式合并。
图 1-1 回放的次序与上面这段叙述并不相同。上面为讲清原理,说的是「先清掉 cccc」;而 DP 重建出的次序是 bb(1,2) → cc(5,6) → cc(7,8) → bbb(3,4,9),先从 bbbb 里删掉两个 b,再分两次清掉 cccc,最后把剩下的三个 b
并成一段。两条次序都到达 ad,长度相同。重建出的是某一条最优次序,取决于
枚举配对时的择优策略,不是叙述里那条。
1.3 · 次序的不唯一性
同一个串可能存在多条到达最短的次序,最终结果串也可能不唯一:abbccaabbc 可消到 a 或 c,长度都是 1。需要计算的是最短可达长度与一组对应的幸存字符,这由区间 DP给出。
2 · 固定次序贪心的失效
2.1 · 从左优先的实现
最直接的想法是从左往右扫,遇到的第一个连续段就立刻删掉;删完因左右贴合可能产生新段,需回退一格继续扫,直到再也找不到连续段。
它一定会终止,因为每次删除都缩短串;最终落在一个「无任何相邻相同字符」的稳定态。问题在于稳定态不止一个,落在哪个取决于消除次序,而这个贪心把次序写死成了永远先删最左,因此它求到的是某个稳定态,不保证是最短的那个。
穷举可以量出差距有多常见。长 10 的串里,2 字母表有 372/1024(36.3%)的串上贪心严格劣于最优,最大差距 3;3 字母表是 9984/59049(16.9%),最大差距 5。字母表越小贪心越吃亏,这与「字母少更容易消」的直觉相反——字母少意味着连续段更多、次序的选择空间更大,先删哪一段的后果也就更严重。
2.2 · 卡住的那一刻
警示 · 反例 abbbbccccbd:贪心从左先删 bbbb,原位置 9 那个落单的 b 就此无法再与任何同字符相邻,停在 abd(长度 3);而先清掉中间的 cccc、让两侧 b 合并再删,可达 ad(长度 2)。贪心的局部决策废掉了一次本可达成的跨越式合并。
并非所有串都让贪心落入次优。abccbbd 上贪心与最优都得到 ad,长度 2。而 abcabc 根本没有任何长度不小于 2 的连续段,一次操作都做不了,两者都停在原串——这不是「次序无差别」,是没有次序可言。差距只在需要先清障碍段、为远处同字符创造合并机会时才出现。
3 · 区间 DP 求最短
3.1 · 子串可消空性的判定
核心子问题是:子串 能否被完全消空,记作 。既然要消空,首字符 必须被删,而它一定是作为某个同字符连续段的一员被删的。只需枚举它与后面某个同字符 配对:若其间的 能消空,这两个字符就会贴成一段;再让这一段继续向右并入更多同字符、整段删除、尾部也消空:
其中 在 时(空串)取真。
配对之后余下的延展交给辅助态 :此刻一段同字符已攒到位置 (段内最右的那个),问 能否整个消空。两条出路。「停」:这段字符(至少两个)就此整段删除,要求尾部 。「续」:右边还有一个同字符在 ,其间的 先消空让它并进来,再递归 。
3.2 · 辅助态的消去
的第二项与 的定义式逐字相同,就是 。所以 不过是 多一条「就地停」的出路,代回后辅助态可完全消去,判定只剩 自身:
注 · 记号
读作「存在某个下标
,取值
」,
是存在量词,
是左开右闭区间,
不取而
取。整行即代码里「只要循环中找到一个满足条件的
就返回 true」的数学写法。与之相对的全称量词
读作「对所有」,表示条件对范围内每个元素都成立,本页未用到。
core/elim.ts 里仍单独保留了
,不是判定需要,而是为了记录每步是「停」还是延展到哪个锚点,供图 1-1 重建删除次序。
按子串长度从小到大填表即可得到全部
。表里同一区间可能有多个字符被并入同一连续段,锚点链因此可以长于两个:aaa 的
锚点是位置 0、1、2 三个,abbacca 的
是 0、3、6。
3.3 · 判定之上的最短化
有了 ,最短化就清楚了。从左到右,每个字符要么作为幸存者保留(计 1),要么属于某个被整体删除的可消空段。幸存者会挡住消除——任意一段的消空只能靠段内字符独立完成,所以保留字符之间的每一段都必须可消空:
复杂度: 的子区间状态共 ,每个状态枚举 个配对位置,整体 时间、 空间。 虽然在实现里写成二维 ,但从 出发的两处递归都原样传递 ,第二维恒为 ,实际只有 个状态、每个 转移,故 一层是 。
判定表覆盖全部 个子区间,一次性回答了「任意子串能否消空」。这既支撑了 的最短化,也解释了单趟贪心为何不可能等价:贪心无法预见「先清掉某个障碍段会让远处变得可消空」这类跨区间的依赖。
4 · 参考文献
本页的问题是 Clickomania(又名 SameGame)限制在单列时的形态,判定「整串能否消空」即该文献中的可解性问题。Biedl 等人证明单列情形两色可在线性时间内解决、任意色数可在多项式时间内解决,而两列五色或五列三色的可解性判定即为 NP 完全 [1]。本页在可消空性判定之上求最短剩余,是同一判定的优化版本。
- Biedl, T. C., Demaine, E. D., Demaine, M. L., Fleischer, R., Jacobsen, L., & Munro, J. I. (2002). The complexity of Clickomania. In R. J. Nowakowski (Ed.), More Games of No Chance (pp. 389–404). Cambridge University Press.
相关链接
- 背包问题九讲 · 动态规划专题 本题的最短化与可消空判定同属区间 DP:状态是子区间,转移枚举配对点 / 切分点。
- 正则表达式 · 从 NFA 到字节码 同样把字符串的结构性消解展开成可单步回放的过程,算法逻辑与渲染分离。
- 列表 diff · 最小差异更新 另一个「在序列上求最优编辑」的区间 / 序列 DP 范例。