湖大CG满分教程:作业训练四编程题20. 回文串(暴力×动态规划算法√)

news/2024/12/22 0:21:12/

问题描述

“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。给你一个字符串,问最少在字符串尾添加多少字符,可以使得字符串变为回文串。

输入格式

有多组测试数据。

每组测试数据第一行是一个正整数N,表示字符串长度,接下来一行是长度为N的字符串,字符串中只有小写字母。

N=0表示输入结束,并且不需要处理。

40%的数列元素个数N 1 ≤ N≤ 100;

30%的数列元素个数N 1 ≤ N≤ 1000;

20%的数列元素个数N 1 ≤ N≤ 10000;

10%的数列元素个数N 1 ≤ N≤ 100000;

输出格式

  对于每组测试数据,输出一个非负整数:添加最少的字符数,可以使得字符串变为回文串。

样例输入

3
aba
4
aaac
0

样例输出

0
3

【算法思想】

  1. 动态规划数组初始化:创建了一个二维数组 dp,大小为 n x n,其中 dp[i][j] 表示子串 s[i..j] 是否是回文串的长度。

  2. 对角线初始化:将对角线上的元素 dp[i][i] 初始化为 1,表示单个字符本身就是回文串。

  3. 动态规划计算:使用两个嵌套的循环,从字符串末尾开始,遍历所有子串。在这个过程中,你检查字符是否相等,然后根据不同情况更新 dp[i][j] 的值。具体来说:

    • 如果 s[i] == s[j],有以下两种情况:
      • j - i <= 1 时,表示当前子串的长度为 2 或者 1,因此直接将 dp[i][j] 设置为 j - i + 1
      • j - i > 1 时,你检查 dp[i + 1][j - 1] 是否表示的子串是回文串,如果是,则更新 dp[i][j]dp[i + 1][j - 1] + 2,表示当前子串的长度为内部回文子串的长度加上 2。
  4. 状态转移方程的核心思想是:通过计算已知较短子串的回文信息,来推导出更长子串的回文信息。的状态转移方程基于如下考虑:

    s[i] == s[j] 时,如果 j - i <= 1,则当前子串长度为 2 或 1,因此是回文串,直接将 dp[i][j] 设置为 j - i + 1。当 s[i] == s[j]j - i > 1 时,首先检查 dp[i + 1][j - 1] 是否表示的子串是回文串。如果是,说明当前子串也是回文串,因此更新 dp[i][j]dp[i + 1][j - 1] + 2,表示当前子串的长度为内部回文子串的长度加上 2。
if (s[i] == s[j]) {if (j - i <= 1) {dp[i][j] = j - i + 1;} else if (dp[i + 1][j - 1]) {dp[i][j] = dp[i + 1][j - 1] + 2;}
}

这个方程的含义是,如果当前子串的两端字符相等,那么要判断该子串是否为回文串,首先考虑 j - i <= 1 的情况,如果成立,说明子串长度为 2 或 1,是回文串,直接标记长度;否则,考虑 dp[i + 1][j - 1] 是否为回文串,如果是,那么当前子串也是回文串,长度为内部回文子串的长度加上 2。

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;int main()
{int n;while(cin >> n && n != 0)  // 循环读取测试数据,直到 n 为 0 结束{string s;cin >> s;  // 读取输入的字符串string x = s;  // 创建一个与输入字符串相同的副本 xreverse(x.begin(), x.end());  // 将副本 x 反转if (x == s)  // 如果副本 x 和原始字符串 s 相同,说明已经是回文串{cout << "0" << endl;  // 输出结果为 0,无需添加字符}else{vector<vector<int>> dp(n, vector<int>(n, 0));  // 创建一个二维数组 dp,用于动态规划for (int i = 0; i < n; i++){dp[i][i] = 1;  // 对角线上的元素置为 1,表示单个字符本身是回文串}int max = 0;  // 用于记录最大的回文子串长度for (int i = s.size() - 1; i >= 0; i--)  // 从字符串末尾开始向前遍历{for (int j = i; j < s.size(); j++)  // 在 i 到字符串末尾范围内遍历{if (s[i] == s[j])  // 如果字符相同{if (j - i <= 1){dp[i][j] = j - i + 1;  // 当 j - i <= 1 时,长度为 2 或者 1,直接标记回文串长度}else if (dp[i + 1][j - 1])  // 当 j - i > 1 时,查看内部子串是否是回文串{dp[i][j] = dp[i + 1][j - 1] + 2;  // 更新回文串长度}}}}// 遍历最后一行,找到最大的回文子串长度for (int i = n - 1; i >= 0; i--){if (dp[i][n - 1] > max){max = dp[i][n - 1];}}cout << n - max;  // 输出最少需要添加的字符数,即字符串长度减去最大回文子串长度}}return 0;
}


http://www.ppmy.cn/news/1015459.html

相关文章

软件性能测试有哪些测试指标?性能测试报告对软件产品起到的作用

在软件开发过程中&#xff0c;性能测试是一个至关重要的环节&#xff0c;主要关注软件系统在不同负载条件下的表现&#xff0c;以评估其稳定性、可扩展性和响应能力。它可以帮助开发人员评估软件系统的质量和性能。 一、软件性能测试的测试指标 性能测试的测试指标直接影响着…

【Linux操作系统】GCC编译与静态库、动态库制作详解

GCC是一款广泛使用的开源编译器&#xff0c;它支持多种编程语言&#xff0c;并且具有强大的编译能力。在软件开发中&#xff0c;我们经常需要将代码编译成可执行文件或者库文件。本文将详细介绍GCC编译过程以及如何制作静态库和动态库。 文章目录 一、GCC编译过程1. 预处理阶段…

[国产MCU]-BL602开发实例-ADC数据采样

ADC数据采样 文章目录 ADC数据采样1、ADC介绍2、ADC驱动API3、ADC使用示例模数转换器(analog-to-digital converter,通常称为ADC)是一种模拟与数字转换器,支持12路外部模拟输入和若干内部模拟信号选择。 BL602的ADC支持以下四种模式:单次单通道转换、连续单通道转换、单次…

在 Linux 上以 All-in-One 模式安装 KubeSphere

官方文档&#xff1a;https://www.kubesphere.io/zh/docs/v3.3/quick-start/all-in-one-on-linux/ 操作系统 最低配置 Ubuntu&#xff1a; 16.04,18.04, 20.04, 22.04 2 核 CPU&#xff0c;4 GB 内存&#xff0c;40 GB 磁盘空间Debian Buste&#xff1a;Stretch 2 核 CPU&am…

Docker基本使用

查看本地镜像 查看本地&#xff1a;docker imagesPull镜像&#xff1a;docker pull nginx:latest登录镜像&#xff1a;docker login hub.docker.com -u **** -p ****制作镜像&#xff1a;docker build -t xxxx:v1push&#xff1a;docker push xxx:v1删除镜像:docker rmi #imag…

MyCat管理及监控——zookeeper及MyCat-web安装

1.MyCat管理 2.MyCat-eye 3.zookeeper安装 第一步&#xff1a;解压 第二部&#xff1a; 切换目录&#xff0c;创建data文件夹 第三步&#xff1a;修改zookeeper配置文件 这样zookeeper安装及配置就完成了 4.MyCat-web安装 注意mycat-web要与zookeeper关联&#xff0c;…

篇六:适配器模式:让不兼容变兼容

篇六&#xff1a;“适配器模式&#xff1a;让不兼容变兼容” 开始本篇文章之前先推荐一个好用的学习工具&#xff0c;AIRIght&#xff0c;借助于AI助手工具&#xff0c;学习事半功倍。欢迎访问&#xff1a;http://airight.fun/ 另外有2本不错的关于设计模式的资料&#xff0c…

Parquet存储的数据模型以及文件格式

文章目录 数据模型Parquet 的原子类型Parquet 的逻辑类型嵌套编码 Parquet文件格式 本文主要参考文献&#xff1a;Tom White. Hadoop权威指南. 第4版. 清华大学出版社, 2017.pages 363. Aapche Parquet是一种能有效存储嵌套数据的列式存储格式&#xff0c;在Spark中应用较多。 …