算法导论_动态规划_最长回文子序列

一、问题的描述

回文序列(Palindromic sequence, Palindrome)是指正向遍历和反向遍历完全相同的序列,例如字符串“AAAAA”显然是一个回文序列,又如字符串“[email protected]”也是一个回文序列。现在,我们要在一个(字符)序列中找出最长回文子序列的长度。例如字符序列"BBABCBCAB",最长回文子序列是“BACBCAB”(可能不唯一),它的长度是7;子序列"BBBBB"和"BBABB"虽然也是回文序列,但却不是最长的,因此不合题意。

二、分析

对任意字符串,如果头和尾相同,那么它的最长回文子序列一定是去头去尾之后的部分的最长回文子序列加上头和尾。如果头和尾不同,那么它的最长回文子序列是去头的部分的最长回文子序列和去尾的部分的最长回文子序列的较长的那一个。

设字符串为s,f(i,j)表示s[i..j]的最长回文子序列。

则有

当i>j时,f(i,j)=0。

当i=j时,f(i,j)=1。

当i<j并且s[i]=s[j]时,f(i,j)=f(i+1,j-1)+2。

当i<j并且s[i]≠s[j]时,f(i,j)=max( f(i,j-1), f(i+1,j) )。

由于f(i,j)依赖i+1,所以循环计算的时候,第一维必须倒过来计算,从s.length()-1到0。

最后,s的最长回文子序列长度为f(0, s.length()-1)。

有如下公式:

代码如下:

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

#define MAX 100

int f[MAX][MAX] = { 0 };
int b[MAX][MAX] = { 0 };
int flag = 0;

void Lps_length(string &str)
{
	int len = str.length();

	for (int i = len - 1; i >= 0; --i)
	{
		f[i][i] = 1;
		for (int j = i+1; j < len; ++j)
		{
			if (str[i] == str[j])
			{
				f[i][j] = f[i + 1][j - 1] + 2;
				b[i][j] = 0;
			}   

			else if (f[i + 1][j] >= f[i][j - 1])
			{
				f[i][j] = f[i + 1][j];
				if(f[i + 1][j] == f[i][j - 1])
					b[i][j] = 2;
				else
				   b[i][j] = -1;
			}

			else
			{
                f[i][j] = f[i][j - 1];
			    b[i][j] = 1;
			}

		}
	}

}

void printf_Lps(int b[MAX][MAX],int i,int j,const string &str)
{
	if (i < 0 || j < 0)
	{
		return;
	}

	if (b[i][j] == 0)
	{
		if (j >= 0 && j <= str.length() - 1)
		{
		cout << str[j];
		}

		if (i == j)
		{
			flag = 1;
		}

		if(flag == 0)
		    printf_Lps(b, i + 1, j - 1,str);
		else
			printf_Lps(b, i - 1, j + 1, str);

	}

	else if (b[i][j] == 2 || b[i][j] == 1)
	{
		if (flag == 0)
		    printf_Lps(b, i, j - 1,str);
		else
			printf_Lps(b, i, j + 1, str);
	}

	else if(b[i][j] == -1)
	{
		if (flag == 0)
		    printf_Lps(b, i + 1, j,str);
		else
			printf_Lps(b, i - 1, j, str);
	}
}

int main()
{

	string str = "GTJYTTHA";

	Lps_length(str);

	for (int i = 0; i <= str.length ()-1; ++i)
	{
		for (int j = 0; j <= str.length() - 1; ++j)
		{
			cout << b[i][j] << "\t";
		}
		cout << endl;
	}

	cout << f[0][str.length() - 1] << endl;

	printf_Lps(b, 0, str.length() - 1,str);

	cout << endl;
	return 0;
}

  上述代码在计算最长回文子序列的长度时计算都是正确的,但是在打印最长回文子序列时有时出现问题,比如在输入character时,输出的是 cara ,而不是carac,调试了很久,也找不出问题,伤心,哪位网友要是看出来问题在哪请留言问题在哪,万分感谢

调试bug是一个痛苦的过程

夜深了,

时间: 2024-10-07 16:08:54

算法导论_动态规划_最长回文子序列的相关文章

最长回文子序列(不连续)以及最长回文子串(连续)

整理了一下关于回文子序列和回文子串的程序. 其中(1)和(2)是采用动态规划的思想写出的回文子序列的程序,这种子序列就是在原始的串中可以不连续,比如对于那种要求删除几个字符来得到最长的回文字符串的题就是这种情况. 比如caberbaf.  最长的子序列是5 abeba 或者abrba.而子串最长只有1 (3)(4)(5)都是最长子串的求法.(3)是暴力求解,(4)是改进的暴力求解.(5)采用的是动态规划的方法. 1 #include <iostream> 2 #include <stri

最长回文子序列

题目:给你一个字符串,求它的最长回文子序列,比如"bbbab" 最长回文子序列是"bbbb" 所以返回4,,"abab"最长子序列是"aba"或者"bab" 所以返回3 思路:和之前做的几道dp不同,,,也是我不够变通,,打dp表的时候总习惯左上到右下的顺序,但是这个顺序却固化了我的思维,忽略了对于题解本身含义的理解....... 这个题从下到上开始打表,最重要的是它的含义,,,知道dp[i][j]意味着什

[最长回文子序列Manacher]4.11终于出线了啊!

Manacher用来求最长回文子序列 1.读入字符串,在每个字符前后加一个没有在原字符串中出现的字符,这样不论是奇数或者偶数个都变成了奇数个 例如: M A N A C H E R # M # A # N # A # C # H # E # R # 2.在开头和末尾再添加一个没有在原字符串中出现的字符,这样就不用讨论越界了 例如: # M # A # N # A # C # H # E # R # $# M # A # N # A # C # H # E # R # \0 3.然后从第一位开始计

soj 4421 最长回文子序列

题意: 给你一个字符串,求该字符串的最长回文子序列长度. 解法: 以前做过连续最长回文子串的长度就是通过构造奇数偶数长度的来做,而本题是不连续. 注意到回文字符串的特点是从左边向右边看和从右边向左边看是一样的效果,那么就可以把目标字符串s导致后产生一个t,子串中如果t和s相同那么这个子串就是回文子串,那么就转化为这两个子串求LCS(longest common subsequent)的问题了. 我的代码: #include <set> #include <map> #include

hdu4757 最长回文子序列(区间DP)

http://acm.hdu.edu.cn/showproblem.php?pid=4745 Problem Description Long long ago, there lived two rabbits Tom and Jerry in the forest. On a sunny afternoon, they planned to play a game with some stones. There were n stones on the ground and they were

[hdu3068 最长回文]Manacher算法,O(N)求最长回文子串

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意:求一个字符串的最长回文子串 思路: 枚举子串的两个端点,根据回文串的定义来判断其是否是回文串并更新答案,复杂度O(N3). 枚举回文串的对称轴i,以及回文半径r,由i和r可确定一个子串,然后暴力判断即可.复杂度O(N2). 在上一步的基础上,改进判断子串是否是回文串的算法.记fi(r)=(bool)以i为对称轴半径为r的子串是回文串,fi(r)的值域为{0, 1},显然fi(r)是关于r

manacher算法求最长回文子序列

一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abccb",最长回文长度为 4,即bccb. 以上问题的传统思路大概是,遍历每一个字符,以该字符为中心向两边查找.其时间复杂度为O(n^2),效率很差. 1975年,一个叫Manacher的人发明了一个算法,Manacher算法(中文名:马拉车算法),该算法可以把时间复杂度提升到O(n).下面来看看马拉车

LPS(最长回文子序列)

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000. Example: Input: "babad" Output: "bab" Note: "aba" is also a valid answer. Example: Input: "cbbd" Ou

最长回文子序列 区间dp

J - 买票回家啦 Time Limit:1000MS    Memory Limit:65535KB    64bit IO Format: SubmitStatusPracticeNBUT 1586 Description 集训要结束了,同学们就准备回家了.好舍不得回家阿.(那就再待一个月嘛,就这么愉快地决定了.)超哥要回家了,可是他没有挤进12306官网, 可怜的他就随便找了个能代购车票的网站.结果,当他付钱时傻眼了,这个网站竟然要验证码.验证码嘛就照着样子输入就好了呀,哦不,这个网站管理