题解:洛谷 P1435 回文子串

【题目来源】

洛谷:P1435 [IOI 2000] 回文字串 - 洛谷

【题目描述】

回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数。

比如 \(Ab3bd\) 插入 \(2\) 个字符后可以变成回文词 \(dAb3bAd\)\(Adb3bdA\),但是插入少于 \(2\) 个的字符无法变成回文词。

注意:此问题区分大小写。

【输入】

输入共一行,一个字符串。

【输出】

有且只有一个整数,即最少插入字符数。

【输入样例】

Ab3bd

【输出样例】

2

【核心思想】

  1. 问题分析:给定一个字符串,求将其变成回文串所需要插入的最少字符数。这是一个线性DP问题,关键在于利用最长公共子序列(LCS)的思想,将问题转化为求字符串与其反转串的LCS长度。

  2. 算法选择

    • 最长公共子序列(LCS):将字符串与其反转串求LCS,得到最长回文子序列长度
    • 问题转化:最少插入字符数 = 字符串总长度 - 最长回文子序列长度
    • 二维DPdp[i][j] 表示字符串 \(s_1[1..i]\)\(s_2[1..j]\) 的LCS长度
  3. 关键步骤

    • 构造反转串:将原字符串 \(s\) 复制并反转得到 \(s_2\)
    • LCS状态转移:对于 \(i\)\(1\)\(n\)\(j\)\(1\)\(n\)
      • \(s_1[i] == s_2[j]\)dp[i][j] = dp[i-1][j-1] + 1,当前字符匹配,LCS长度加1
      • \(s_1[i] \neq s_2[j]\)dp[i][j] = max(dp[i-1][j], dp[i][j-1]),取上方或左方的最大值
    • 计算答案ans = n - dp[n][n],总长度减去最长回文子序列长度即为最少插入字符数
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n^2)\),双重循环遍历两个字符串
    • 空间复杂度:\(O(n^2)\),二维DP数组(可优化为 \(O(n)\)
  5. LCS求回文插入最少字符的核心思想

    • 对称性利用:回文串正读反读相同,将字符串与其反转串求LCS,得到的即为最长回文子序列
    • 问题转化:不需要直接求最少插入数,而是转化为求最长回文子序列,再用总长度减去它
    • 最优子结构:LCS具有最优子结构性质,当前状态由子问题最优解推导
    • 空间优化:因为只依赖上一行和当前行左侧,可用滚动数组将空间优化至 \(O(n)\)
    • 适用于"求字符串变成回文串的最少插入/删除次数"类问题

【解题思路】

【算法标签】

普及 #线性DP-一维

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 1005;  // 定义最大字符串长度

string s1, s2;        // s1: 原始字符串,s2: 反转后的字符串
int dp[N][N];         // DP数组,用于存储最长公共子序列长度

int main()
{
    // 输入原始字符串
    cin >> s2;

    // 复制原始字符串并反转
    string s1 = s2;
    reverse(s2.begin(), s2.end());

    // 在字符串前添加空格,使索引从1开始
    s1 = " " + s1;
    s2 = " " + s2;

    int len = s1.size();  // 获取字符串长度(包含前导空格)

    // 动态规划计算最长公共子序列
    for (int i = 1; i <= len; i++)
    {
        for (int j = 1; j <= len; j++)
        {
            if (s1[i] == s2[j])
            {
                // 字符匹配,长度加1
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }
            else
            {
                // 字符不匹配,取上方或左方的最大值
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    // 输出需要插入的最少字符数(总长度减去最长回文子序列长度)
    cout << len - dp[len][len];

    return 0;
}

【运行结果】

Ab3db
2
posted @ 2026-06-25 19:14  团爸讲算法  阅读(12)  评论(0)    收藏  举报