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. es6 常用的语法

    1.es6 模块化 你import 和 export export default 为默认到处,而export能导出多个方法或变量. 2. es6——class与普通构造函数的区别 class的继承方 ...

  2. 60、saleforce的future方法

    测试future方法的异步执行 public with sharing class FutureSample { //future在自己线程中运行,直到资源可用才运行 @future public s ...

  3. Missing artifact net.sf.json-lib:json-lib:jar:2.4

    Missing artifact net.sf.json-lib:json-lib:jar:2.4 出现上述这种错误就是JAR没有引入进来 这时候发现是因为JDK版本的问题,所以需要在加一句 < ...

  4. 使用Microsoft.Practices.Unity 依赖注入 转载https://www.cnblogs.com/slardar1978/p/4205394.html

    Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,它支持常用的三种依赖注入方式:构造器注入 ...

  5. javascript闭包实现缓存小案例

    ​ /* * 闭包实现缓存 * 属性:有个键--值 --->所以可以将缓存数据存放在一个对象中 * 方法:缓存存储 setCache * 缓存的获取 getCache * */ function ...

  6. NIO浅析(二)

    一:前言 在(一中了解了NIO中的缓冲区和通道),通过本文章你会了解阻塞和非阻塞,选择器,管道 二:完成NIO通信的三要素 * 1.通道(Channel):负责连接* java.nio.channel ...

  7. Rust <10>:宏导出、导入

    源 crate 中使用 #[macro_export] 属性标记的宏,调用者可在导入此 crate 时添加 #[macro_use] 属性使用. 没有 #[macro_export] 的宏,外部不可见 ...

  8. python学习笔记:接口开发——flask Demo实例

    举例1,返回当前时间接口 ''' 初始化:所有的Flask都必须创建程序实例, web服务器使用wsgi协议,把客户端所有的请求都转发给这个程序实例 程序实例是Flask的对象,一般情况下用如下方法实 ...

  9. JavaFX教程

    JavaFX是Java的下一代图形用户界面工具包.JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序. JavaFX允许开发人员快速构建丰富的跨平台应用程序.JavaFX通 ...

  10. Emacs 25.1 error solved: url-http-create-request: Multibyte text in HTTP request

    Emacs 25.1 error solved: url-http-create-request: Multibyte text in HTTP request */--> code {colo ...