寻找两个字符串中最大相同子序列(动态规划解法及STL优解)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


解题思路参考(感谢!!!)

前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、怎么寻找两个字符串中最大相同子序列

当我们看到这个问题的时候,最多可能想的就是暴力解法,不停比较两个字符串中的相同部分,但是无疑,暴力解法在很多oj上是很难通过的!!!
所有我们就需要去寻找一些算法,以达到可以优化解题代码,使得其简单高效。

二、通过例题解析

1.动态规划解法

假设寻找字符串“abcbced”与字符串“acbcbcef”的最大相同子序列
算法思路:
1、把两个字符串分别以行和列组成一个二维矩阵。

2、比较二维矩阵中每个点对应行列字符中否相等,相等的话值设置为1,否则设置为0。

3、通过查找出值为1的最长对角线就能找到最长公共子串。

针对于上面的两个字符串我们可以得到的二维矩阵如下:
在这里插入图片描述
此时运用dp就可以计算最大公共子串
在这里插入图片描述
可以通过一个二维数组来存结果->

if (s1[i] == s2[j])
	{
		a[i][j] = a[i-1][j-1] + 1;
	}

代码:

#include <iostream>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		string s1;
		string s2;
		cin >> s1;
		cin >> s2;
		int maxx = -9999;//存取最大长度
		int a[100][100];//存取结果
		memset(a, 0, sizeof(a));//初始化为0
			for (int i = 0; i < s1.size(); i++)
			{
				for (int j = 0; j < s2.size(); j++)
				{
					if (s1[i] == s2[j])
					{
						a[i+1][j+1] = a[i][j] + 1;//不断更新相同字符
						maxx = max(maxx, a[i + 1][j + 1]);//更新最大相同子序列
					}
				}
			}
			cout << maxx << endl;
	}
	return 0;
}

2.STL优解

因为在解决该问题时,其实是不停对字符串进行处理,所有在STL中对string容器有许多的使用技巧:
我们在解决该问题的时候会用到主要两方面:
a:字符串的拼接
b:字符串的查找和替换

2->string容器的拼接
string s;
a:s+=(const char str)//重载+=操作符,实现将char类型字符串str拼接到字符串s后。
b:s+=(const string &str)//重载+=操作符,实现将字符串类型str拼接到字符串s后。
c:s+=(const char c)//重载+=操作符,实现将字符c拼接到字符串s后
d:s.append(const char *s1)//将char *类型字符串s1拼接到字符串s后
e:s.append(const string &s1)//将字符串类型s1拼接到字符串s后
f:s.append(const chars,int n)//将char *类型字符串拼接到字符串s后
g:s.append(const string &s1,int pos,int n)//将字符串s1从pos开始的n个字符串拼接到字符串s后
3->string容器的查找和替换
string s;
a:int k=s.find(const string &s1,int pos=0)//查找字符串s1在字符串s中从pops开始第一次出现的位置,若找到返回该位置,反之返回“-1”;
b:int k=s.find(const char *s1,int pos=0)//查找char 类型字符串s1第一次出现的位置,从pos开始查找,若存在返回该位置,反之返回“-1”;
c:int k=s.find(const chars1,int pos,int n)//从pos位置开始查找char
类型字符串s1的前n个字符,第一次出现的位置,若存在返回该位置,反之返回“-1”。
d:int k=s.find(const char c,int pos=0)//从pos位置开始查找字符串s中字符c第一次出现的位置,若存在则返回该位置,反之返回“-1”;
e:int k=s.rfind(const string &str,int pos=s.size())//同上a,从后往前找,寻找最后一次出现的位置
f:int k=s.rfind(const char *s1,int pos=s.size())//同上b,从后往前找,寻找最后一次出现的位置
g:int k=s.rfind(const chars,int pos=s.size(),int n)//同上c,从后往前找,寻找最后一次出现的位置
h:int k=s.rfind(const char c,int pos=s.size(),int n)//同上d,从后往前找,寻找最后一次出现的位置
i:s.replace(int pos,int n,const string &str)//将字符串s从pos位置开始后n个字符,替换为字符串str。
j:s.replace(int pos,int n,const char std)//将字符串s从pos位置开始后n个字符,替换为char型字符串str。

STL解法的思路就像暴力解法一样,但是在进行“搜索操作”时,可以使用STL进行优化。
算法思路:
1:寻找字符串s1中的所有子串。
2:在字符串s2中寻找所有s1的子串,如果存在就记录该子串为相同子序列。
3:通过max不断更新最大相同子序列。

#include <iostream>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		string s1;
		string s2;
		cin >> s1;
		cin >> s2;
		int maxx = -9999;
			for (int i = 0; i < s1.size(); i++)
			{
				for (int j = 1; j <= s1.size()-i; j++)
				{
					string str;
					str.append(s1, i, j);//s1的子串
					s2.find(str, 0);
					int xx = str.size();
					if (s2.find(str, 0) != -1)	//相同子序列
					{
						maxx = max(xx, maxx);//更新最大相同子序列
					}
				}
			}
			cout<<maxx<<endl;
	}
	return 0;
}

3.实例(cf ->div3 #710 c)

题目链接
1->题目
outputstandard output
You are given the strings a and b, consisting of lowercase Latin letters. You can do any number of the following operations in any order:

if |a|>0 (the length of the string a is greater than zero), delete the first character of the string a, that is, replace a with a2a3…an;
if |a|>0, delete the last character of the string a, that is, replace a with a1a2…an−1;
if |b|>0 (the length of the string b is greater than zero), delete the first character of the string b, that is, replace b with b2b3…bn;
if |b|>0, delete the last character of the string b, that is, replace b with b1b2…bn−1.
Note that after each of the operations, the string a or b may become empty.

For example, if a=“hello” and b=“icpc”, then you can apply the following sequence of operations:

delete the first character of the string a ⇒ a=“ello” and b=“icpc”;
delete the first character of the string b ⇒ a=“ello” and b=“cpc”;
delete the first character of the string b ⇒ a=“ello” and b=“pc”;
delete the last character of the string a ⇒ a=“ell” and b=“pc”;
delete the last character of the string b ⇒ a=“ell” and b=“p”.
For the given strings a and b, find the minimum number of operations for which you can make the strings a and b equal. Note that empty strings are also equal.

Input
The first line contains a single integer t (1≤t≤100). Then t test cases follow.

The first line of each test case contains the string a (1≤|a|≤20), consisting of lowercase Latin letters.

The second line of each test case contains the string b (1≤|b|≤20), consisting of lowercase Latin letters.

Output
For each test case, output the minimum number of operations that can make the strings a and b equal.
2->分析:a:求出最大相同子序列
b:最大操作数=字符串s1的长度+字符串s2的长度-2*最大相同子序列长度
代码:

#include <iostream>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int main()
{
	ll t;
	cin >> t;
	while (t--)
	{
		string s1;
		string s2;
		cin >> s1;
		cin >> s2;
		int maxx = -9999;
			for (int i = 0; i < s1.size(); i++)
			{
				for (int j = 1; j <= s1.size()-i; j++)
				{
					string str;
					str.append(s1, i, j);
					s2.find(str, 0);
					int xx = str.size();
					if (s2.find(str, 0) != -1)
					{
						maxx = max(xx, maxx);
					}
				}
			}
			if (maxx == -9999)
			{
				cout << s1.size() + s2.size() << endl;
			}
			else
			{
				int sum = s1.size() + s2.size() - 2 * maxx;
				cout << sum << endl;
			}
	}
	return 0;
}

如有错误,恳请指正!

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值