P1435 回文字串
P1435 回文字串
题目背景
IOI2000第一题
题目描述
回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数。
比如 “Ab3bd”插入2个字符后可以变成回文词“dAb3bAd”或“Adb3bdA”,但是插入少于2个的字符无法变成回文词。
注:此问题区分大小写
输入输出格式
输入格式:
一个字符串(0<strlen<=1000)
输出格式:
有且只有一个整数,即最少插入字符数
输入输出样例
Ab3bd
2
分析:
解题思路:该题说是考察如何将一个字符串添加成一个回文串的,不如说是一道求最长公共自序列的变式题,为啥这么说呢?肯定是有原因在里面的
首先,我们要摸清回文串的特性,回文就是正着读反着读一样,一种非常对称不会逼死强迫症的字符串;这就是我们的突破口。。。你难道以为是逼死强迫症么?哈哈,太天真了,突破口其实是因为回文正着读反着读都相同的特性。。。这样我们就可以再建一个字符数组存储倒序的字符串
- 我们先分析下样例:ab3bd,
它的倒序是:db3ba
这样我们就可以把问题转化成了求最长公共自序列的问题,为啥可以这么转化呢?
它可以这么理解,正序与倒序“公共”的部分就是我们回文的部分,如果把正序与倒序公共的部分减去你就会惊奇的发现剩余的字符就是你所要添加的字符,也就是所求的正解
ad da把不回文的加起来就是我们梦寐以求的东西:回文串(卧槽?太没追求了)
把ad,da加起来成回文串就是adb3bda,所以这个问题就可以转化成了求最长公共自序列的问题,将字符串的长度减去它本身的“回文的”(最长公共自序列)字符便是正解
- 找到解题思路后我们就可以开始写了,最长公共自序列问题是个经典的dp问题,
最容易想到的方法就是开个二维数组dp【i】【j】,i,j分别代表两种状态;
那么我们的动态转移方程应该就是if(str1[i] == str2[j]) dp[i][j]=dp[i-1][j-1]+1;
Else dp[i][j] = max(dp[i-1][j], dp[i][j-1];
依此即可解出最长公共自序列,用字符串长度减去即是正解
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
using namespace std;
int n;
int dp[][];
char str1[],str2[];
int main()
{
//freopen("palindrome.in", "r", stdin);
//freopen("palindrome.out", "w", stdout);
scanf("%s", str1+);
n = strlen(str1+);
for(int i = ; i <= n; i++)
str2[i] = str1[n-i+]; //做一个逆序的字符串数组
for(int i = ; i<=n; i++)
for(int j = ; j <= n; j++)
if(str1[i] == str2[j])
dp[i][j] = dp[i-][j-] + ; //最长公共自序列匹配
else
dp[i][j] = max(dp[i-][j], dp[i][j-]); //不匹配的往下匹配状态
printf("%d\n", n-dp[n][n]); //字符串长度减去匹配出的最长公共自序列的值
return ; //即需要添加的字符数
}
可这并不是最优解法,只是能ac这道题而已 若是将内存限制改为2MB呢?
不过,没关系,正常开一个5001*5001的数组一定会爆掉的,此时你是不是在思考另一种解决方案来优化一下空间复杂度,如果我可以把它用一维数组代替二维数组中的状态量是不是也可以求出正解
没错。它真的能
求出正解;
如果你仔细研究一下就会发现每次搜索到str1的第i个元素的时候,数组dp【】【】真正使用到的元素仅仅是dp【i】【j】和dp【i-1】【k】(0 <= k <= n(n = strlen(str1))
即dp【】【】的第一下标从0-->i-2就没有用处了,因此我们可以开辟两个滚动数组来降低空间复杂度
Dp1【】用来记录当前状态,dp2【】用来记录之前的状态也就相当于刚才的dp【i-1】【j】
动态转移方程应该这么表达if(str1[i] == str2[i]) dp1[j] = dp2[j-1] +1;
Else dp1[j] = max(dp1[j-1], dp2[j]);
源代码在此,天下我有:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
using namespace std;
int n;
int dp1[],dp2[]; //此处用两个滚动数组记录,一个记录之前的状态,一个记录此时的状态
char str1[],str2[];
int main()
{
//freopen("palindrome.in", "r", stdin);
//freopen("palindrome.out", "w", stdout);
scanf("%s", str1+);
n = strlen(str1+);
for(int i = ; i <= n; i++)
str2[i] = str1[n-i+]; //做一个逆序的字符串数组
for(int i = ; i<=n; i++)
{
for(int j = ; j <= n; j++)
if(str1[i] == str2[j])
dp1[j] = dp2[j-]+; //“发现”匹配就记录
else
dp1[j] = max(dp1[j-],dp2[j]); //不匹配就匹配后面的状态
memcpy(dp2, dp1, sizeof(dp1)); //记录之前的状态“滚动”匹配
}
printf("%d\n", n-dp1[n]); //字符串长度减去匹配出的最长公共自序列的值
return ; //即需要添加的字符数
}
ps:
滚动数组交换的时候,感觉直接交换索引比直接交换dp1和dp2整个数组要优。
P1435 回文字串的更多相关文章
- P1435 回文字串(LCS问题)
题目背景 IOI2000第一题 题目描述(题目链接:https://www.luogu.org/problem/P1435) 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成 ...
- 洛谷P1435 回文字串(dp)
题意 题目链接 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成回文词.此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数. 比如 “Ab3bd”插入2个字符后可 ...
- 洛谷P1435 回文字串
题目背景 IOI2000第一题 题目描述 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成回文词.此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数. 比如 “A ...
- 洛谷 P1435 回文字串
题目传送门 解题思路: 就是求一个字符串的最长回文子序列的长度,然后用整个的长度减去最长回文子序列的长度 AC代码: #include<iostream> #include<cstd ...
- P1435 回文字串(DP)
题目描述 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成回文词.此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数. 比如 "Ab3bd"插 ...
- 求字符串的最长回文字串 O(n)
昨天参加了某公司的校园招聘的笔试题,做得惨不忍睹,其中就有这么一道算法设计题:求一个字符串的最长回文字串.我在ACM校队选拔赛上遇到过这道题,当时用的后缀数组AC的,但是模板忘了没写出代码来. 回头我 ...
- hihocoder 第一周 最长回文字串
题目1 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程 ...
- POJ 3974 最长回文字串(manacher算法)
题意:给出一个字符串,求出最长回文字串. 思路:一开始我直接上了后缀数组DC3的解法,然后MLE了.看了DISCUSS发现还有一种计算回文字串更加优越的算法,就是manacher算法.就去学习了一下, ...
- 2238"回文字串"报告
题目描述: 回文串,就是从前往后和从后往前看都是一样的字符串.那么现在给你一个字符串,请你找出该字符串中,长度最大的一个回文子串. 输入描述: 有且仅有一个仅包含小写字母的字符串,保证其长度不超过50 ...
随机推荐
- LOJ 2720 「NOI2018」你的名字——后缀自动机
题目:https://loj.ac/problem/2720 自己总是分不清 “SAM上一个点的 len[ ] ” 和 “一个串的前缀在 SAM 上匹配的 len ”. 于是原本想的 68 分做法是, ...
- SAS 读取数据文件
每次读取数据时需要告诉SAS3件事:1:数据存在哪里?2:数据的形式3:创建的数据集的类型(永久/临时) 1 读取SAS数据集 DATA temp; /*temp 为创建的数据集名称*/ INFILE ...
- MySQL教程和使用手册
MySQL 教程 MySQL 教程.MySQL 安装.MySQL 管理.MySQL PHP 语法.MySQL 连接.MySQL 创建数据库.MySQL 删除数据库.MySQL 选择数据库.MySQL ...
- PHP面试 MySQL查询优化
MySQL查询优化 面试题一 请简述项目中优化SQL语句执行效率的方法,从那些方面,SQL语句性能如何分析? 优化查询过程中的数据访问.优化长难的查询语句.优化特定类型的查询语句 分析SQL语句方法 ...
- WebBrowser是IE内置的浏览器控件
WebBrowser是IE内置的浏览器控件.WebBrowser是IE内置的浏览器控件.WebBrowser是IE内置的浏览器控件.重要的事情说三遍,原因是一开始使用的时候就在这踩了坑. WebBro ...
- shell awk匹配字符串(从配置文件)
配置文件 config.properties xxx_yyy_lib_path="路径" xxx_yyy_bin_path="路径" 想通过shell来读入路径 ...
- Django框架(十五)—— forms组件、局部钩子、全局钩子
目录 forms组件.局部钩子.全局钩子 一.什么是forms组件 二.forms组件的使用 1.使用语法 2.组件的参数 3.注意点 三.渲染模板 四.渲染错误信息 五.局部钩子 1.什么是局部钩子 ...
- 使用yarn搭建vue项目
今天尝试了一下用yarn的方式搭建vue项目,方法其实是和npm的用法一样.但是在创建过程中报错了.现在整理一下,便于后期查错时使用. 以windows系统为例 1.全局安装yarn,三种方式 官网上 ...
- mysql中tinyint(1)与tinyint(2)的区别
tinyint 型的字段如果设置为UNSIGNED类型,只能存储从0到255的整数,不能用来储存负数.tinyint 型的字段如果不设置UNSIGNED类型,存储-128到127的整数. 1个tiny ...
- Python判断一个字符串中是否存在多个子串中的一个
在使用python的开发过程中,常常需要判断,字符串中是否存在子串的问题, 但判断一个字符串中是否存在多个字串中的一个时,如if (a or b) in c或者if x contains a|b|c| ...