P1435 回文字串

题目背景

IOI2000第一题

题目描述

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

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

注:此问题区分大小写

输入输出格式

输入格式:

一个字符串(0<strlen<=1000)

输出格式:

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

输入输出样例

输入样例#1:

Ab3bd
输出样例#1:

2
 
分析:
1、模型就是“公共子序列”的变式
2、模型要确保建对,毕竟知道公共子序列的变式之后还有细节要注意
3、用滚动数组优化空间
 
 

分析:

洛谷题解,讲的相当详细

解题思路:该题说是考察如何将一个字符串添加成一个回文串的,不如说是一道求最长公共自序列的变式题,为啥这么说呢?肯定是有原因在里面的

  1. 首先,我们要摸清回文串的特性,回文就是正着读反着读一样,一种非常对称不会逼死强迫症的字符串;这就是我们的突破口。。。你难道以为是逼死强迫症么?哈哈,太天真了,突破口其实是因为回文正着读反着读都相同的特性。。。这样我们就可以再建一个字符数组存储倒序的字符串

  2. 我们先分析下样例:ab3bd,

它的倒序是:db3ba

这样我们就可以把问题转化成了求最长公共自序列的问题,为啥可以这么转化呢?

它可以这么理解,正序与倒序“公共”的部分就是我们回文的部分,如果把正序与倒序公共的部分减去你就会惊奇的发现剩余的字符就是你所要添加的字符,也就是所求的正解

ad da把不回文的加起来就是我们梦寐以求的东西:回文串(卧槽?太没追求了)

把ad,da加起来成回文串就是adb3bda,所以这个问题就可以转化成了求最长公共自序列的问题,将字符串的长度减去它本身的“回文的”(最长公共自序列)字符便是正解

  1. 找到解题思路后我们就可以开始写了,最长公共自序列问题是个经典的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 回文字串的更多相关文章

  1. P1435 回文字串(LCS问题)

    题目背景 IOI2000第一题 题目描述(题目链接:https://www.luogu.org/problem/P1435) 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成 ...

  2. 洛谷P1435 回文字串(dp)

    题意 题目链接 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成回文词.此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数. 比如 “Ab3bd”插入2个字符后可 ...

  3. 洛谷P1435 回文字串

    题目背景 IOI2000第一题 题目描述 回文词是一种对称的字符串.任意给定一个字符串,通过插入若干字符,都可以变成回文词.此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数. 比如 “A ...

  4. 洛谷 P1435 回文字串

    题目传送门 解题思路: 就是求一个字符串的最长回文子序列的长度,然后用整个的长度减去最长回文子序列的长度 AC代码: #include<iostream> #include<cstd ...

  5. P1435 回文字串(DP)

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

  6. 求字符串的最长回文字串 O(n)

    昨天参加了某公司的校园招聘的笔试题,做得惨不忍睹,其中就有这么一道算法设计题:求一个字符串的最长回文字串.我在ACM校队选拔赛上遇到过这道题,当时用的后缀数组AC的,但是模板忘了没写出代码来. 回头我 ...

  7. hihocoder 第一周 最长回文字串

    题目1 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程 ...

  8. POJ 3974 最长回文字串(manacher算法)

    题意:给出一个字符串,求出最长回文字串. 思路:一开始我直接上了后缀数组DC3的解法,然后MLE了.看了DISCUSS发现还有一种计算回文字串更加优越的算法,就是manacher算法.就去学习了一下, ...

  9. 2238"回文字串"报告

    题目描述: 回文串,就是从前往后和从后往前看都是一样的字符串.那么现在给你一个字符串,请你找出该字符串中,长度最大的一个回文子串. 输入描述: 有且仅有一个仅包含小写字母的字符串,保证其长度不超过50 ...

随机推荐

  1. html生成pdf

    /** * 生成pdf * @param string $html 需要生成的内容 */ function pdf($html='<h1 style="color:red"& ...

  2. Docker Machine 管理-创建machine(16)

    对于 Docker Machine 来说,术语 Machine 就是运行 docker daemon 的主机.“创建 Machine” 指的就是在 host 上安装和部署 docker.先执行 doc ...

  3. cookie的使用说明

    cookie的英文意思是饼干的意思,实质上是键值对组成的字典.就是说你访问某一个网址,服务器给你一个东西,你收到东西,并且贴上了一个标签.下次你访问服务器的时候,请求带有标签.这样服务器给你之后,就会 ...

  4. elementUI中input输入框,强制输入数字,并限制输入长度

    <el-input v-model="item.userScore" onkeyup="this.value=this.value.replace(/[^\d.]/ ...

  5. HTML5: HTML5 MathML

    ylbtech-HTML5: HTML5 MathML 1.返回顶部 1. HTML5 MathML HTML5 可以在文档中使用 MathML 元素,对应的标签是 <math>...&l ...

  6. (55)C# windows 消息

    窗体捕获消息 namespace WindowsFormsApp1 { public partial class Form1 : Form { public Form1() { InitializeC ...

  7. JS制作二级联动

    JS制作二级联动 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://ww ...

  8. 08 java代码块的概述和分类

    08.01_面向对象(代码块的概述和分类) A:代码块概述 在Java中,使用{}括起来的代码被称为代码块. B:代码块分类 根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代 ...

  9. 04 循环结构概述和for语句的格式及其使用

    04.01_Java语言基础(循环结构概述和for语句的格式及其使用) A:循环结构的分类 for,while,do…while B:循环结构for语句的格式: for(初始化表达式;条件表达式;循环 ...

  10. POJ 3641 Pseudoprime numbers (数论+快速幂)

    题目链接:POJ 3641 Description Fermat's theorem states that for any prime number p and for any integer a ...