回文分割的最小切割次数问题(进阶版:带权值)
字数 1484 2025-11-07 12:33:00
回文分割的最小切割次数问题(进阶版:带权值)
题目描述
给定一个字符串s,以及一个权值数组weights,其中weights[i]表示将字符串s的第i个字符作为分割点(即在s[i]和s[i+1]之间进行切割)的代价。我们的目标是将字符串s分割成若干个子串,使得每个子串都是回文串,并且所有分割点的代价之和最小。如果无法分割成全部是回文串,则返回-1。
解题过程
-
问题分析
这是一个典型的区间动态规划问题,需要在字符串s上找到一组分割点,使得每个分割后的子串都是回文串,并且分割点的总代价最小。与基础版不同,这里每个分割点的代价可能不同,增加了问题的复杂性。 -
定义状态
设dp[i][j]表示将子串s[i:j+1](即从索引i到j的子串)分割成回文子串的最小切割代价。如果s[i:j+1]本身是回文串,则不需要切割,代价为0。否则,我们需要在i到j-1之间寻找分割点k,使得分割后的左右两部分都是回文串,并且总代价最小。 -
状态转移方程
- 如果s[i:j+1]是回文串,则dp[i][j] = 0。
- 否则,遍历所有可能的分割点k(i ≤ k < j),将子串分割为s[i:k+1]和s[k+1:j+1]两部分。总代价为左右两部分的切割代价之和,加上在k处切割的代价weights[k](即在s[k]和s[k+1]之间切割的代价)。
状态转移方程为:
dp[i][j] = min(dp[i][k] + dp[k+1][j] + weights[k]),其中k从i到j-1。 - 如果无法分割(即所有分割方案都无效),则dp[i][j] = ∞。
-
初始化
- 单个字符的子串一定是回文串,因此dp[i][i] = 0。
- 对于长度大于1的子串,初始值设为∞,表示尚未找到有效分割方案。
-
计算顺序
按照子串长度从小到大计算:先计算所有长度为2的子串,然后长度为3,依此类推,直到整个字符串s[0:n-1]。 -
判断回文子串
为了高效判断s[i:j+1]是否为回文串,可以预先计算一个二维数组isPal[i][j],表示s[i:j+1]是否为回文串。计算isPal时,同样使用动态规划:- isPal[i][j]为真,当且仅当s[i] == s[j]且isPal[i+1][j-1]为真(或j-i ≤ 1)。
-
最终结果
整个字符串的最小切割代价为dp[0][n-1]。如果dp[0][n-1]为∞,则返回-1,否则返回该值。 -
示例
假设s = "aab",weights = [1, 2, 3](长度为n-1=2)。- 计算isPal:
"a"(索引0-0)是回文;"a"(1-1)是回文;"b"(2-2)是回文;
"aa"(0-1)是回文;"ab"(1-2)不是回文;"aab"(0-2)不是回文。 - 计算dp:
dp[0][0]=0, dp[1][1]=0, dp[2][2]=0;
长度2:dp[0][1]=0("aa"是回文),dp[1][2]=∞("ab"不是回文且无法分割);
长度3:dp[0][2] = min(
dp[0][0] + dp[1][2] + weights[0] = 0 + ∞ + 1 → ∞,
dp[0][1] + dp[2][2] + weights[1] = 0 + 0 + 2 = 2
) = 2。
最终结果为2。
- 计算isPal:
通过以上步骤,我们可以高效地求解带权值的回文分割最小切割问题。