赞
踩
给定两个 string 字符串,找出他们的最长公共子序列(Longest Common Sequence,LCS)。
例如 string A = “BDCABA“,string B = ”ABCBDAB“,他们的LCS = 4。
求最长公共子序列的经典方法属于一种动态规划(Dynamic Programming,DP)。
而动态规划的两个基本要素为:① 最优子结构 ② 重叠子问题
① 最优子结构
设 X = x1 x2 … xn Y = y1 y2 … ym
若 xn == ym,说明该元素一定存在于LCS中,
故只要求 LCS(Xn-1,ym-1),这是一个最优的子问题。
若 xn != ym,则继续分类缩小问题的范围。
故只要求 max{LCS(Xn-1,Ym),LCS(Xn,Ym-1)} 即可。
② 重复子问题
LCS(X,Y):LCS(Xn-1,Ym-1),LCS(Xn-1,Ym),LCS(Xn,Ym-1)
LCS(Xn-1,Ym):LCS(Xn-2,Ym-1),LCS(Xn-2,Ym),LCS(Xn-1,Ym-1)
……
如图会有很多重复的子问题,若用递归做时间会以指数增长。
用 dp 做的直接进行“查表”即可。
综上:
参考代码:
int LCS(string str1, string str2){ // 初始化第一行和第一列 for(int i = 0; i <= len1; i++){ dp[i][0] = 0; } for(int i = 0; i <= len2; i++){ dp[0][i] = 0; } // 构建dp数组 for(int i = 1; i <= len1; i++){ for(int j = 1; j <= len2; j++){ if(str1[i] == str2[j]){ // 如果该位置上的字符相同 dp值 = 没有当前字符时的LCS值+1 dp[i][j] = dp[i-1][j-1]+1; } else{ // 如果不同 dp值 = 单字符串去掉当前字符时的两个LCS中的最大值 dp[i][j] = max(dp[i-1][j], dp[i][j-1]); } } } return dp[len1][len2]; }
问题描述如下:
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABECDCBABC
则程序应该输出:
3
也就是说至少需要添加多少个字符才可以变成一个镜像串。
怎么联系到最长公共子序列呢?
因为原本是一个镜像串,镜像串的特点就是正序和逆序相同。
我们可以利用这一点,把脱落后的密码串进行反转,再跟反转前的密码串进行比对。
找到最长的公共子序列之后,其余剩下没有匹配成功的字符就是需要添加的字符。
这样就可以保证添加最少的字符来还原一个镜像串。
参考代码如下:
// 第七届蓝桥杯第九题 #include<iostream> using namespace std; int **arr; // 翻转 string reverse(string str){ string sub = str; for(int i = 0; i < sub.length()/2; i++){ char ch = sub[i]; sub[i] = sub[sub.length()-1-i]; sub[sub.length()-1-i] = ch; } return sub; } // 求最长公共子序列 int getLCS(string str1, string str2){ // 动态创建二维数组 arr = new int*[str1.length()+1]; for(int i = 0; i <= str1.length(); i++){ arr[i] = new int[str2.length()+1]; } // 将第一行和第一列初始化为0 for(int i = 0; i <= str1.length(); i++){ arr[i][0] = 0; } for(int i = 0; i <= str2.length(); i++){ arr[0][i] = 0; } // 根据公式计算二维数组 for(int i = 1; i <= str1.length(); i++){ for(int j = 1; j <= str2.length(); j++){ if(str1[i] == str2[j]){ arr[i][j] = arr[i-1][j-1]+1; } else if(arr[i-1][j] > arr[i][j-1]){ arr[i][j] = arr[i-1][j]; } else{ arr[i][j] = arr[i][j-1]; } } } // 返回两个字符串的LCS return arr[str1.length()][str2.length()]; } int main(){ string str; while(cin >> str){ string sub = reverse(str); int len = getLCS(str, sub); // 用原长减去LCS就是答案 cout << str.length()-len << endl; for(int i = 0; i < str.length()+1; i++){ delete []arr[i]; } delete []arr; } return 0; }
【END】感谢观看
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。