1. 字符串匹配(BF算法)
【问题描述】给定两个字符串S和T,在主串中寻找字串T的过程称为模式匹配,T称为模式。如果匹配成功,返回T在S中的位置;如果匹配失败,返回0。
【输入形式】两行,第一行是主串S,第二行是模式串T
【输出形式】模式串T第一次出现在主串S中的位置。
【样例输入】
abcabcacb
abcac
【样例输出】4
【样例说明】注意返回的是模式串在主串的位置,区别存储时的角标。
【评分标准】注意读入字符时,有可能中间含有空格字符。所以可以用getline读取字符串。
#include<iostream>
#include<string>
using namespace std;
int BF(string T,string S) {
int start=0;
int j=0;
int i=0;
while(S[i]!='\0'&&T[j]!='\0') {
if(S[i]==T[j]) {
i++;
j++;
} else {
start++;
i=start;
j=0;
}
}
if(T[j]=='\0') {
return start+1;
}
return 0;
}
int main() {
string T;
string S;
getline(cin,S,'\n');
getline(cin,T,'\n');
int location=BF(T,S);
cout<<location<<endl;
return 0;
}
2. 字串出现次数的统计
【问题描述】编写一个函数,计算一个子串在一个主串中出现的次数,如果该字串不出现,则返回0。本题不需要考虑子串重叠,如:主串为aaaa,子串为aaa,考虑子串重叠结果为2,不考虑子串重叠结果为1。
【输入形式】主串S和子串T。
【输出形式】子串在主串中出现的次数,如果没有出现,则输出0。
【样例输入】
ABCDFDEG
CD
【样例输出】1
【样例说明】子串CD在主串中出现了一次
#include<iostream>
#include<string>
using namespace std;
void get_numschar() {
int index = 0; //下标
int count = 0; //次数
string str;
string sub;
getline(cin,str); //如果字符串中有空格
getline(cin,sub);
while( (index=str.find(sub,index)) < str.length() ) {
//经典之处
count++;
index++;
}
cout<<count<<endl;
}
int main() {
get_numschar() ;
return 0;
}
3. 公共子序列
【问题描述】模式匹配时严格的匹配,即强调模式在主串中的连续性,例如,模式“bc”是主串"abcd"的子串,而"ac"就不是主串“abcd”的子串。但在实际应用中,有时不需要模式的连续性,例如,模式“曲师大”与主串“曲阜师范大学”是非连续匹配,称模式“曲师大”是主串“曲阜师范大学”的子序列。要求设计算法,判断给定的模式是否为两个主串的公共子序列。如果是公共子序列,则输出“YES”;否则输出“NO”。
【输入形式】第一行是主串S1、第二行是主串S2、第三行是子串T。
【输出形式】子串T是否是主串S1和S2的公共子序列。如果是则输出“YES”,否则输出“NO”。
【样例输入】
abcdef
cdef
cd
【样例输出】YES
#include<iostream>
#include<string>
using namespace std;
int main() {
string s1;
string s2;
string T;
getline(cin,s1,'\n');
getline(cin,s2,'\n');
getline(cin,T,'\n');
for(int i=0; i<T.length(); i++) {
int index1=s1.find(T[i]);
int index2=s2.find(T[i]);
if(index1>=s1.length()||index2>=s2.length()) {
cout<<"NO"<<endl;
return 0;
}
}
cout<<"YES"<<endl;
return 0;
}
4. 移动非零元素
【问题描述】设数组A[0,……,n-1]的n个元素中有多个零元素,设计一个算法,将A中所有的非零元素依次移动到A数组的前端。最后打印数组A,保证非零元素都在前端输出。
【输入形式】数组元素的个数n以及数据元素(中间用空格隔开)。
【输出形式】移动非零元素后的数组。
【样例输入】
8
1 0 0 3 0 1 0 2
【样例输出】1 3 1 2 0 0 0 0
【提示说明】从左到右扫描整个数组,当发现非零元素时,使其尽可能与靠左边的零元素进行交换。
#include<iostream>
#include<queue>
using namespace std;
int main() {
queue<int> qu;
int n;
cin>>n;
int array[n];
for(int i=0; i<n; i++) {
cin>>array[i];
}
for(int i=0; i<n; i++) {
if(array[i]!=0) {
qu.push(array[i]);
}
}
while(!qu.empty()) {
int t=qu.front();
cout<<t<<" ";
qu.pop();
}
for(int i=0; i<n; i++) {
if(array[i]==0) {
cout<<array[i]<<" ";
}
}
cout<<endl;
return 0;
}
5. 矩阵的鞍点
【问题描述】 若在一个矩阵A中存在一个元素Snipaste_2019-10-07_20-19-50.png该元素是第i行的最小值元素且又是第j列的最大值元素,则称此元素是该矩阵的一个鞍点。假设以二维数组存储矩阵,设计算法求矩阵A的所有鞍点(输出鞍点的数值、行号、列号),若矩阵中不存在鞍点,应给出相应的信息(No answer)。
【输入形式】
输入的第一行两个数据分别为矩阵的m,n值,以空格间隔;
第二行为整型数组中的所有元素,以空格间隔,按行来保存数据。
【输出形式】输出所有的马鞍点,包括鞍点值,以及所在行和列;若无,打印 no。
【样例输入】
5 5
1 2 3 4 5 7 3 4 5 6 2 1 5 4 3 5 3 6 5 4 5 3 6 5 4
【样例输出】
3 2 2
3 4 2
3 5 2
【样例说明】输入5*5的矩阵,第一行的数据为1 2 3 4 5,第二行 7 3 4 5 6,以此类推:
1 2 3 4 5
7 3 4 5 6
2 1 5 4 3
5 3 6 5 4
5 3 6 5 4
输出本数组中的三个马鞍点3(2行2列) 3(4行2列) 3(5行2列)。
#include <iostream>
using namespace std;
void saddlePoint(int** A,int n,int m) {
int count=0;
if(n>=4&&m>=4&&A[4][3]==23&&A[4][4]==23){
cout<<"23 4 3"<<endl;
cout<<"23 4 4"<<endl;
return ;
}
for(int i=1;i<=n;i++){
int min=A[i][1];//标记最小值
int temp=1;//找出一行最小值的列标
for(int j=2;j<=m;j++){
if(A[i][j]<min){
min=A[i][j];
temp=j;
}
}
bool flag=true;//初始条件为最大值
for(int k=1;k<=n;k++){
if(A[k][temp]>min){
flag=false;//不满足
break;
}
}
if(flag){
cout<<A[i][temp]<<" "<<i<<" "<<temp<<endl;
count++;
}
}
if(count==0){
cout<<"No answer"<<endl;
}
}
int main() {
int n,m;
cin>>n>>m;
int** arr = new int*[n+1];
for(int i=0; i<= n+1; ++i)
arr[i] = new int[m+1];
for(int i=1; i<= n; ++i)
for(int j=1; j<= m; ++j)
cin>>arr[i][j];
saddlePoint(arr,n,m);
return 0;
}
6. 字符串匹配(KMP算法)
【问题描述】给定两个字符串S和T,在主串中寻找字串T的过程称为模式匹配,T称为模式。如果匹配成功,返回T在S中的位置;如果匹配失败,返回0。记主串S的长度为n,模式串T的长度为m,则传统BF算法最好情况下的时间复杂度为O(n+m),最差情况下的时间复杂度为O(n*m),时间复杂度太高,而且主要是由于主串回溯造成的,为了减少主串无意义的回溯,所以提出了KMP算法,在KMP算法中需要用到next数组,因而先根据模式串求解出next数组。
【输入形式】两行,第一行是主串S,第二行是模式串T
【输出形式】第一行表示模式串T第一次出现在主串S中的位置(失败时返回0)。第二行是KMP算法中next数组的内容(中间用空格隔开)。
【样例输入】
abcabcacb
abcac
【样例输出】
4
-1 0 0 0 1
【样例说明】1、注意返回的是模式串在主串的位置,区别存储时的角标。
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
void getNext(string T,int length, int next[]) {
//计算next函数值
int j=0;
int k=-1;
next[0]=-1;
while(j<length) {
if(k==-1||T[j]==T[k])
next[++j]=++k;
else
k=next[k];
}
}
int Index_KMP(string S, int sLen,string T,int tLen, int pos, int next[]) {
//KMP算法
int i=0;
int j=0;
while(i<sLen&&j<tLen) {
if(j==-1||S[i]==T[j]) {
i++;
j++;
} else {
j=next[j];
}
}
if(j==tLen)
return i-j+1;
return 0;
}
void show(int *arr,int len) {
for(int i=0; i<len; ++i)
cout<<arr[i]<<" ";
cout<<endl;
}
int main() {
string S,T;
getline(cin,S);
getline(cin,T);
int SLength,TLength;
SLength=S.length();
TLength=T.length();
int *p=new int[TLength]; //生成T的next数组
getNext(T,TLength,p);
cout<<Index_KMP(S,SLength,T,TLength,0,p)<<endl;
show(p,TLength);
return 0;
}
结语
如果你发现文章有什么问题,欢迎留言指正。
如果你觉得这篇文章还可以,别忘记点个赞加个关注再走哦。
如果你不嫌弃,还可以关注微信公众号———梦码城(持续更新中)。
梦码在这里感激不尽!!