最长公共子序列(动态规划求法)

来源:互联网 发布:mac anaconda使用教程 编辑:程序博客网 时间:2024/05/01 00:09

最长公共子序列

题目:给定一个字符串s(1 <=  s <= 1000),你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
    输出需要删除的字符个数。

通过这道题我们了解一下动态规划,并通过动态规划完成该题目!

解题思路:

提到回文串,利用回文串的特点,想到将源字符串逆序,“回文串”(不一定连续)相当于顺序没变
求原字符串和其反串的最大公共子序列(不是子串,因为可以不连续)的长度(使用动态规划很容易求得),然后用原字符串的长度减去这个最大公共子串的长度就得到了最小编辑长度。

(1)把字符串旋转形成另外一个字符串,称为旋转字符串;
(2)求原字符串s1与旋转字符串s2中,最长公共子串的长度;
(3)删除的字符数目 = 原字符串的长度 - 最长公共子串的长度。
需要解决的子问题:
求两个字符串s1和s2中最长公共子串的长度。
子问题的求解方式:动态规划
设 MaxLen(i, j)表示s1左边i个字符与s2左边j个字符的最长公共子串长度,则子问题的解为MaxLen(strlen(s1), strlen(s2));
MaxLen(i, j)的求解方式为:
若s1第i个字符与s2第j个字符相匹配,则 MaxLen(i, j) = MaxLen(i - 1, j - 1)+1;
否则:MaxLen(i, j) = max(MaxLen(i - 1, j), MaxLen(i, j - 1))

图解:

设:字符串有n个元素,则构建(n+1)*(n+1)的矩阵,并将第0行和第0列全置为0;

我们以字符串“abca”为例,求它的最长子序列:

为了便于理解,我将源代码与上图放在一起以便大家对照理解。

#include<iostream>#include<string>#include<algorithm>using namespace std;const int MAX = 1001; //比字符串长度要大1int MaxLen[MAX][MAX]; //最长公共子序列,动态规划求法int maxLen(string s1, string s2){int length1 = s1.size();int length2 = s2.size();for (int i = 0; i < length1; ++i){MaxLen[i][0] = 0;     //将矩阵第0行第0列置0MaxLen[0][i] = 0;}for (int i = 1; i <= length1; ++i){for (int j = 1; j <= length2; ++j){if (s1[i - 1] == s2[j - 1]){MaxLen[i][j] = MaxLen[i - 1][j - 1] + 1;}else{MaxLen[i][j] = max(MaxLen[i - 1][j], MaxLen[i][j - 1]);}}}return MaxLen[length1][length2];}int main(){string s;while (cin >> s){int length = s.size();if (length == 1){cout << 0 << endl;continue;}//利用回文串的特点处理string s2 = s;reverse(s2.begin(), s2.end());int max_length = maxLen(s, s2);cout << length - max_length << endl;}return 0;}


1 0
原创粉丝点击