📅  最后修改于: 2023-12-03 14:55:21.009000             🧑  作者: Mango
给定一个字符串 $s$,转换成回文串的成本定义为在 $s$ 中插入或删除字符的次数,使得 $s$ 变成一个回文串。求将 $s$ 转换成回文串的最小成本。
设 $s$ 长度为 $n$,$dp_{i,j}$ 表示将 $s$ 的第 $i$ 到 $j$ 个字符组成的字符串变为回文串的最小成本,则有:
最终答案即为 $dp_{1,n}$。
时间复杂度 $O(n^2)$。
从左往右遍历字符串 $s$,以每个字符为中心向两边扩展,分别计算添加左右两边字符的代价。最终答案即为所有代价的最小值。
中心扩展的时间复杂度为 $O(n^2)$,加上字符串的遍历,总的时间复杂度为 $O(n^3)$。
Manacher 算法也是一种中心扩展的方法,但它有一个优秀的性质:能够直接求出以每个字符为中心的最长回文子串。
具体操作如下:
首先对字符串进行预处理,将每个字符之间添加一个哨兵字符,比如将字符串 $s$ 转化为 $#s_1#s_2#...#s_n#$(假设 $n$ 为奇数);
维护两个指针 $r$ 和 $c$,分别表示已知最右端为 $r$ 的最长回文串的中心位置,和该回文串的右端位置。初始化 $r=0, c=0$;
从左往右遍历字符串,枚举每个字符作为中心的情况。设中心位置为 $i$,则:
若 $i<r$,则 $dp_i=\min(dp_{2\cdot c-i}, r-i)$,其中 $dp_i$ 表示以 $i$ 为中心的最长回文子串的半径(也就是长度除以 $2$);
利用中心扩展的思想,尝试将该回文子串扩展至最长。具体实现时,只需比较左右两边的字符是否相等即可;
若扩展后的新回文串的右端位置比当前已知的最长回文串的右端位置更远,则对 $r$ 和 $c$ 进行更新。
Manacher 算法的时间复杂度为 $O(n)$。
以上三种方法都能求出将给定字符串转换为回文串的最小成本。动态规划是最直观的方法,但时间复杂度较高。中心扩展能够求出以每个字符为中心的最长回文子串,但时间复杂度更高。Manacher 算法则是一种在时间和空间两方面都比较优秀的解法。