您的位置:首页 > 其它

字符串回文子序列问题

2015-11-05 20:25 267 查看
【问题1】求字符串回文子序列的个数

问题:

给定字符串,求它的回文子序列个数。回文子序列反转字符顺序后仍然与原序列相同。例如字符串aba中,回文子序列为”a”, “a”, “aa”, “b”, “aba”,共5个。内容相同位置不同的子序列算不同的子序列。

分析与解法:

(注意:与子串不同,子序列可以是不连续的,只要元素的前后相对位置不变。)

解法一:递归

假设s[0 … n-1]是给定的序列,长度为让 c(0,n-1)表示序列s[0 … n-1] 的回文子序列的个数。

如果s的最后一个元素和第一个元素是相同的:c(1, n-1) + c(0, n-2) + 1。

如果s的最后一个元素和第一个元素是不同的,这时:c(0, n-1) = c(1, n-1) + c(0, n-2) - c(1, n-2) ,即”ab”+ “ba” - “b” 。

可以写出如下递归程序:

int count(string str, int i, int j)//调用时count(str, 0, n-1);
{
if(i == j)//一个元素即是它本身
return 1;
if(i > j)//只计算顺序时的子序列
return 0;
if(str[i] != str[j])//若首尾不同
return count(str, i + 1, j) + count(str, i, j - 1) - count(str, i + 1, j - 1);
else//若首尾相同
return count(str, i + 1, j) + count(str, i, j - 1) + 1;
}


解法二:动态规划

解法一中存在重复计算的问题,且当字符串长度过大时,递归的时间复杂度会很高。可以采用动态规划的方法。

用dp[j][j+i]表示s[j…j+i]之间的回文子序列的个数,

如果s的最后一个元素和第一个元素是相同的:dp[j][j+i] = dp[j+1][j+i] + dp[j][j+i-1] + 1。

如果s的最后一个元素和第一个元素是不同的,这时:dp[j][j+i] = dp[j+1][j+i] + dp[j][j+i-1] - dp[j+1][j+i-1],即”ab”+ “ba” - “b”。

这里可以将二维数组dp的值列出,方便理解。其中橙色区域的数值只与黄色区域的数值有关,以dp[0][1]为例,若首尾元素相同,则等于dp[1][1] + dp[0][0] + 1;若首尾元素不同,则等于dp[1][1] + dp[0][0] - dp[1][0]。



int count(string str,int n)
{
int dp[MAXSIZE][MAXSIZE], tmp;
memset(dp,0,sizeof(dp));//dp数组中所有元素置0
for(int i=0; i<n; i++) dp[i][i] = 1;//一个元素即是它本身
//i表示当前长度为i+1的子序列
for(int i=1; i<n; i++)
{
tmp = 0;
//考虑所有连续的长度为i+1的子串. 该串为 str[j, j+i]
for(int j=0; j+i<n; j++)
{
if(str[j] == str[j+i])//若首尾相同
tmp = dp[j+1][j+i] + dp[j][j+i-1] + 1;
else//若首尾不同
tmp = dp[j+1][j+i] + dp[j][j+i-1] - dp[j+1][j+i-1];
dp[j][j+i] = tmp;
}
}
//返回串 str[0][n-1] 的结果
return dp[0][n-1];
}


【问题2】求字符串回文子序列的最大长度

http://www.acmerblog.com/longest-palindromic-subsequence-5721.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: