1312. 让字符串成为回文串的最少插入次数
考点
- 区间DP
- 回文序列
思路
一、问题描述
给定一个字符串 \(s\),允许在任意位置插入字符,目标是使最终字符串成为回文串,并且插入次数最少。
要求:
- 只能插入字符,不能删除或修改原有字符;
- 插入的字符可以是任意字符;
- 返回最少插入次数。
二、问题建模的核心思想
1. 从“插入”到“保留”
设原字符串长度为 \(n\)。
任何通过插入得到的回文串,都必然完整包含原字符串作为子序列。 因此,最终回文串可以被理解为:
- 保留原字符串中的某些字符(按原顺序)
- 对未保留的字符,通过插入的方式进行补齐
关键问题转化为:
在原字符串中,最多能保留多少个字符,使它们本身构成一个回文序列?
这正是最长回文子序列(LPS, Longest Palindromic Subsequence)问题。
2. 最少插入次数与 LPS 的关系
设:
- 原字符串长度为 \(n\)
- 最长回文子序列长度为 \(L\)
则有: \[ \boxed{ \text{最少插入次数} = n - L } \] 理由:
- LPS 中的 \(L\) 个字符可以直接作为最终回文串的“骨架”;
- 剩下的 \(n - L\) 个字符,必须通过插入其对称字符来补齐;
- 不可能通过更少的插入覆盖这些未被保留的字符。
因此,本题的本质是:
求字符串的最长回文子序列长度。
三、最长回文子序列的区间 DP 建模
1. 状态定义
使用区间动态规划。
定义: \[ f[i][j] = \text{子串 } s[i..j] \text{ 的最长回文子序列长度} \] 其中:
- \(i, j\) 为 1-based 下标
- \(1 \le i \le j \le n\)
2. 边界条件
- 单个字符天然是回文:
\[ f[i][i] = 1 \]
3. 状态转移方程
考虑区间两端字符 \(s[i]\) 与 \(s[j]\):
情况一:两端字符相等
\[ s[i] = s[j] \]
这两个字符可以作为回文序列的一对端点,因此: \[ \boxed{ f[i][j] = f[i+1][j-1] + 2 } \] 含义是:
- 中间区间 \(s[i+1..j-1]\) 的最长回文子序列
- 再加上左右这两个相等字符
情况二:两端字符不相等
\[ s[i] \ne s[j] \]
最长回文子序列必然来自以下两种情况之一:
- 不使用左端字符:来自 \(f[i+1][j]\)
- 不使用右端字符:来自 \(f[i][j-1]\)
取最大值: \[ \boxed{ f[i][j] = \max(f[i+1][j],\ f[i][j-1]) } \]
4. 计算顺序
由于状态 \(f[i][j]\) 依赖更短的区间,需按区间长度递增的顺序进行 DP:
- 先处理长度为 1
- 再处理长度为 2、3、……
- 最终得到 \(f[1][n]\)
四、最终答案的计算
得到最长回文子序列长度 \(f[1][n]\) 后: \[ \boxed{ \text{最少插入次数} = n - f[1][n] } \]
五、算法复杂度分析
- 状态数量:\(O(n^2)\)
- 每个状态转移:\(O(1)\)
时间复杂度: \[ O(n^2) \] 空间复杂度: \[ O(n^2) \] 在 \(n \le 500\) 的约束下可以稳定通过。
六、完整参考实现(附注释)
1 | class Solution { |