2022-10-12 算法题-1 最长公共子序列LCS

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

思路:
先求字符串s的反转串rs,然后求s和rs的最大公共子序列(子序列不要求连续而子串要求连续,字符串和其反转串的最大公共子序列一定是对称的),则最大公共子序列的长度即为最大回文串的长度

最长公共子序列LCS 参考链接

1. 子序列
一个序列A中任意删除若干项,剩余的序列叫做A的一个子序列,也可以认为是从序列A按原顺序保留任意若干项得到的序列,对于一个长度为n的序列,它一共有2^n个子序列(子序列不是子集,它和原始序列的元素顺序相关)
2. 公共子序列
如果序列C既是A的子序列,也是B的子序列,则称其为A和B的公共子序列,空序列是任何两个序列的公共子序列
3. 最长公共子序列
A和B的公共子序列中长度最长的叫AB的最长公共子序列,最长公共子序列的不唯一
4. LCS算法-使用动态规划求解
·A有n个元素,B有m个元素,用Ax表示序列A的连续前x项构成的子序列,即Ax=a1,a2…ax,By=b1,b2…by,用LCS(x,y)表示它们的最长公共子序列长度,用L(x,y)表示Ax和By的一个最长公共子序列,原问题就等价于求LCS(m,n)。
(1) 当Ax=By=t时,其L(Ax,By)的最后一项一定为t,假设L(x,y)最后一项不是t,则要么L(x,y)为空序列,要么Aa=Bb≠t,且a<x,b<y。无论哪种情况都可以把t接到L(x,y)后面得到更长的公共子序列。如果从Ax中删掉最后一项ax得到Ax-1,从By中删掉最后一项by得到By-1,则从L(x,y)中也删掉最后一项t得到的序列时L(x-1,y-1)。因此有:
LCS(Ax,By)=LCS(x-1,y-1)+1
(2) Ax≠By时,假设t=L(Ax,By)或者L(Ax,By)是空序列
如果t≠Ax,则有L(x,y)=L(x-1,y),LCS(x,y)=LCS(x-1,y)
如果t≠By,则有L(x,y)=L(x,y-1),LCS(x,y)=LCS(x,y-1)
所以有LCS(x,y)=max(LCS(x-1,y),LCS(x,y)=LCS(x,y-1))
(3) 所以有:
在这里插入图片描述
5. 代码:C++实现

#include<iostream> 
#include<string.h>
using namespace std;
 
//递归的方法 
//注意 A和B分别为输入的字符串前面加上一个' '空的字符,是为了解决边界问题. 
int LCS(string A, string B, int x, int y)
{
	if(x==0 || y==0)	//边界 
		return 0;
	else				//非边界位置 
	{
		if(A[x] == B[y])	//最后一个字符相同 
			return LCS(A, B, x-1, y-1) + 1;
		else
			return max(LCS(A, B, x, y-1), LCS(A, B, x-1, y));
	}
}
 
int main()
{
	string A = "BCBACABBACDX";
	string B = "BCXYDADJL";		// A 和 B的LCS为BCAD 
	int x = A.length();
	int y = B.length();
	A = ' ' + A;
	B = ' ' + B;
	int result = LCS(A, B, x, y);
	cout << result << endl;
	
	return 0; 
} 
#include<iostream> 
#include<string.h>
using namespace std;
 
//循环打表 的方式求LCS[x][y] 
int main()
{	
	string A = "BCBACABBACDX";
	string B = "BCXYDADJL";		// A 和 B的LCS为BCAD 
	int x = A.length();
	int y = B.length();
	A = ' ' + A;
	B = ' ' + B;
 
	int i, j;
	int ** LCS = new int*[x+1];
	for(i=0;i<=x;i++)
	{
		LCS[i] = new int[y+1];
		for (j=0;j<=y;j++)
			LCS[i][j] = 0;	//LCS[i][j]用来存储 
	}
		
	for(i=0;i<=x;i++)
		for(j=0;j<=y;j++)
			if(i==0 || j==0)
				LCS[i][j] = 0;
			else
			{
				if(A[i] == B[j])
					LCS[i][j] = LCS[i-1][j-1] + 1; 
				else
					LCS[i][j] = max(LCS[i-1][j], LCS[i][j-1]);
			}
	
	int result = LCS[x][y];
	cout << result << endl;
	
	return 0; 
}
  1. 题目实现:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
 
string converseString(string str){
	int size = str.size();
	if (size < 2) return str;
	int front = 0, rear = size - 1;
	while(front < rear){
		char temp = str[front];
		str[front] = str[rear];
		str[rear] = temp;
		front++;
		rear--;
	}
	return str;
}
 
 
int max(int a, int b){
	return a>b ? a : b;
}
 
 
int GetLCS(string s1, string s2){
	int size = s1.size();
	int curMax = 0;
	vector<vector<int> > DP(size + 1, vector<int>(size + 1, 0));
	for (int i = 0; i <= size; i++)
	{
		DP[i][0] = 0;
		DP[0][i] = 0;
	}
	for (int i = 1; i <= size; i++)
		for (int j = 1; j <= size; j++){
			if (s1[i - 1] == s2[j - 1])
				DP[i][j] = DP[i - 1][j - 1] + 1;
			else
				DP[i][j] = max(DP[i][j - 1], DP[i - 1][j]);
			if (DP[i][j] > curMax)
				curMax = DP[i][j];
		}
	return curMax;
}
 
int core(string str){
	string converseStr = converseString(str);
	return str.size() - GetLCS(str, converseStr);
}
 
int main(int argc, char* argv[])
{
	cout << core("google") << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值