数据结构(字符串和多维数组)

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”。

【样例输入】

扫描二维码关注公众号,回复: 12641718 查看本文章
 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;
}

结语

如果你发现文章有什么问题,欢迎留言指正。
如果你觉得这篇文章还可以,别忘记点个赞加个关注再走哦。
如果你不嫌弃,还可以关注微信公众号———梦码城(持续更新中)。
梦码在这里感激不尽!!

猜你喜欢

转载自blog.csdn.net/qq_45724216/article/details/112135333