先举两个例子吧:
模式“AC”是主串“Alpha Cat”和主串“ACCEPT”的公共子序列。
模式“abc”是主串“abcde”和主串“adbec”的公共子序列。
由此可见公共子序列的定义就是说,在主串中有序的存在模式的全部字符,可以是不连续的,然后我百度了一下,关于公共子序列的概念可以参考子数列的概念。
子数列
在数学中,某个数列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新数列。
概念介绍
在数学中,某个数列的子数列是从最初数列通过去除某些元素(有限或无限项)但不破坏余下元素的相对位置(在前或在后)而形成的新数列。
正式的说,假设X是集合而(ak)k∈K是X中的数列,这里的K={1,2,3,...,n},如果(ak)是有限数列,且K=
,当(ak)是无限数列。则(ak)的子数列是形如 的数列,这里的(nr)是在索引集合K中严格递增数列。
代码如下:
java:
package pat;
import java.util.*;
public class Main
{
public static void judge(String t,String demo)
{
int index = 0;
for (int i = 0; i < t.length(); i++) {
if (t.charAt(i) == demo.charAt(index)) {//charAt的功能
index++; // 相等的话,指针右移一位
if (index >= demo.length()) {//统计index出现的数量,这里计算的是index是否偏移的次数是否跟demo的长度相等,
//如果相等就意味着demo中的元素全部找到,那么匹配成功
System.out.println("Yes");
return;
}
}
}
System.out.println("NO");
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);//定义输入流
try
{
while(true)
{
String demo = scanner.nextLine();
String t = scanner.nextLine();
String t2=scanner.nextLine();
judge(t,demo);
judge(t2,demo);
}
}
finally
{
scanner.close();//防止资源泄漏
}
}
}
测试案例:
C++:
#include<iostream>
#include<string>
using namespace std;
bool judge(string a,string demo) //demo是短的那个模式
{
for(int i=0;i<a.length();i++)//遍历主串
if(a[i]==demo[0])//如果第一个字符可以匹配,就从模式删除那个字符,如果最后删成了空串,那就意味着匹配成功了
{
demo=demo.erase(0,1); //demo=demo.substr(1,demo.length()-1);//前后两句话等效,都为删除第一个字符
if(demo.length()==0)//如果最后删成了空串,那就意味着匹配成功了
return 1;
}
//获得字符串s中 从第0位开始的长度为5的字符串//默认时的长度为从开始位置到尾
return 0;
}
int main()
{
string demo;
cout<<"请输入模式串:"<<endl;
cin>>demo;//此处的cin会把回车留在缓冲区,如果再去缓冲区读取,读到的是回车就会直接结束一个数据的输入
string a,b;
cout<<"请输入两个主串"<<endl;
getchar();//用途是从缓冲区吃掉一个字符,这里用来吃掉上两行注释中说的回车符;
getline(cin,a);//读取一行数据到缓冲区
getline(cin,b);
if(judge(a,demo)&&judge(b,demo))//如果A和B两个数据都能满足
cout<<"恭喜!是这两个主串的子串"<<endl;
else
cout<<"这个模式不是这两个主串的子串"<<endl;
return 0;
}
测试案例:
java版的思路就是通过charat来用程序自己内置的函数来找到位置,而这对应了C++里面的find 函数
C++版的思路就是找一遍,如果某字符和模式串首字符吻合就不断通过消模式串的第一个元素,如果空串说明匹配成功
注意点1
charAt(int index)方法是一个能够用来检索特定索引下的字符的String实例的方法.
charAt()方法返回指定索引位置的char值。索引范围为0~length()-1.
如: str.charAt(0)检索str中的第一个字符,str.charAt(str.length()-1)检索最后一个字符.
注意点2
substr(C++语言函数)
substr是C++语言函数,主要功能是复制子字符串,要求从指定位置开始,并具有指定的长度。如果没有指定长度_Count或_Count+_Off超出了源字符串的长度,则子字符串将延续到源字符串的结尾。
erase在之前的博文中介绍过,在这题中大展身手。
注意点3
scanner输入语法输入完以后需要用类似scanner.close()的语法来关闭流,防止资源泄漏,养成良好习惯
如果在之前的cin后面直接getline,那么这个getline就会直接结束,因为错误发生在缓冲区,cin不会去吃回车,于是回车留在缓冲区,getline会读取回车然后结束,所以这里用了一个getchar从缓冲区里读取一个字符,但不会赋值给任何东西,因为我的目的是把那个回车符给干掉,然后就可以正常了
在最后,附上自己匆忙之间上课做的队列做法,做烦了,但是就是想用用队列,emmmmm
#include<iostream>
#include<queue>
#include<cstdlib>
#include<string>
using namespace std;
bool judge_childstr(string a,string demo)
{
//0 is the true
queue<char> Q;
int judge=1;
int n=0;
for(int i=0;i<demo.size();i++)
{
Q.push(demo[i]);
}
for(int j=0;j<a.size();j++)
{
char temp=Q.front();
cout<<"当前正在匹配字符:";
cout<<temp<<endl;
cout<<"主串中的字符是:";
cout<<a[j]<<endl;
if(temp==a[j])
{
n++;
cout<<"当前以匹配的长度 "<<n<<endl;
Q.pop();
}
}
cout<<"模式长度"<<a.size()<<endl;
if(n==demo.size())
{
cout<<"这个子串匹配成功"<<endl;
return 0;
}
else
return 1;
}
int main()
{
//Q.push('c');
// char a=Q.top();
// cout<<a;
//test
string demo;
cout<<"请输入模式串:"<<endl;
cin>>demo;
string a,b;
cout<<"请输入两个主串"<<endl;
// int sync(void);
getchar();
getline(cin,a);
getline(cin,b);
int judge=1;
judge-=judge_childstr(a,demo);
judge-=judge_childstr(b,demo);
cout<<endl;
if(judge==1)
{
cout<<"这个模式是这两个主串的子串"<<endl;
}
else
{
cout<<"这个模式不是这两个主串的子串"<<endl;
}
system("pause");
return 0;
}
课上老师说的BF算法是通过指针,我的算法比bf少了一行,这两种算法于这种很类似,接下来我想去试下kmp,敲完的话会更新在这篇博文的下方。
未完待续。。。