【算法】小矩阵在大矩阵中是否存在的检测(深信服笔试题之牛逼病毒检测)

前几天参加了深信服的笔试,第一题就是这个检测小矩阵在大矩阵中是否存在。
当时想法是有的,不过具体实现出了点问题,笔试应该挂了。
时隔两天,我还是觉得要把题目弄完,也算是一种积累吧。
愿你我都能遇见最好的自己。

题目描述

  1. 请输入一个数T,表示接下来要输入的矩阵组数。T<50
  2. 在一行内输入两个整数N、M,他们分别表示大矩阵(方阵)和小矩阵(方阵)的阶数。 0<N<10000; 0<M<=N.
  3. 输出T行:即每一组的结果输出一行,如果小矩阵存在于大矩阵中,则输出 yes, 若是小矩阵不在大矩阵中,则输出 no.
  4. 实例:
输入:
1
3 2
# . #
. # .
# # #
# .
. #
输出:
yes
输入组数为3:
3
3 2
# . #
. # .
# # #
# .
. #
3 2
# . #
. # .
# # #
. #
# #
3 2
# . #
. # .
# # #
# #
. #
输出:
yes
yes
no

要完成的工作就是以上所述。接下来我将使用矩阵的双指针法来完成该任务。

代码实现

//NiuBiVirus 
#include<iostream>
using namespace std;

int main(){
	int n;
	cin>>n;            //输入的组数n 
	if(n<1 || n>50){
		cout<<"输入不符合规则"<<endl;
		return 0; 
	} 
	int i=0;
	int N,M;           //分别定义数组的大小 
	
	while(i<n){
		i++; 
		cin>>N>>M;
		char s1[N][N];          //定义数组 1 并用 for循环输入 
		for(int j=0;j<N;j++){
			for(int k=0;k<N;k++){
				cin>>s1[j][k];
			}
		}
		
		char s2[M][M];           //定义数组 2 并用 for循环输入
		for(int j=0;j<M;j++){
			for(int k=0;k<M;k++){
				cin>>s2[j][k];
			}
		}
		
		//测试输出 
//		for(int j=0;j<N;j++){
//			for(int k=0;k<N;k++){
//				cout<<s1[j][k]<<' ';
//			}
//			cout<<endl;
//		}

		int l1=0,l2=0;      // 用数字定义数组1的指针  
    	int k1=0,k2=0;      // 用数字定义数组2的指针
    	int d1=0,d2=0;      // 用于锚定数组1对应数组2头部的位置
    	int key=0;          // 一个记录全正确比较的值 
		int ch=0;
		while(1){
			
    		if(ch==1){                        //设定判别参数判定锚点是否更改 
    			d1=l1;
    			d2=l2;
			}	
    		if(s1[l1][l2]==s2[k1][k2]){       //比较数组1与数组2的指针域指向的值是否相等 
    			key++;                       
				ch=0;
				l2++;                         //若相等则数组1和数组2的指针都向后移动 
    			k2++;
    			
				if(k2==M){                    //若数组2的指针溢出,则指针换行 
    				l1++;
    				l2=l2-M;                  //注意换行后数组1的指针指向,应与上一行的位置联系起来 
    				k1++;
    				k2=0;
				}
				
				if(k1==M){                    //若数组2的列指针溢出,则比较完成。 
					cout<<"yes"<<endl; 
					break;
				}
    		}	
    		

    		else {
    			ch = 1;
    			if(l2>0){                     //注意指针的变化情况,若在上面改变了指针应改回来再执行后续 
					l2--;
    				k2--;
				} 
    			key=0;                        // key值清零表示需从头再全部比较数组2 
    			d2++;                         //数组1与2的对应值不相等时,移动大数组的锚点指针                          
    			k2=0;
    			
    			if(d2==N-M+1){                // 若发现大数组剩下的列数小于小矩阵时可直接换行 
    				d1++;
    				d2=0;
    				k1=0;
    				k2=0;
				}
				if(d1==N-M+1){                //  若发现大数组剩下的矩阵小于小矩阵时可直接结束 
					cout<<"No"<<endl;
					break;
				}
				l1=d1;
				l2=d2;
			}
			
//			cout<<"l1:"<<l1<<endl;
//			cout<<"l2:"<<l2<<endl;
//			cout<<"k1:"<<k1<<endl;
//			cout<<"k2:"<<k2<<endl; 
//			cout<<"key:"<<key<<endl;
//			cout<<endl;
    		
		}
		
		// key值比较。 
//		if(key==M*M){
//			cout<<11111111;
//		}
//		else cout<<22222222;

	}
	
	return 0;
	
} 

运行结果

在这里插入图片描述
在这里插入图片描述

如上图,题目要求的任务能够实现,不过输出于输入是交叉进行,可做适当修改美化输出。

优化后的代码

//NiuBiVirus 
#include<iostream>
using namespace std;

int main(){
	int n;
	cin>>n;            //输入的组数n 
	if(n<1 || n>50){
		cout<<"输入不符合规则"<<endl;
		return 0; 
	} 
	int i=0;
	int N,M;           //分别定义数组的大小 
	
	//优化输出:
	int res[n] = {0};
	 
	while(i<n){
		cin>>N>>M;
		char s1[N][N];          //定义数组 1 并用 for循环输入 
		for(int j=0;j<N;j++){
			for(int k=0;k<N;k++){
				cin>>s1[j][k];
			}
		}
		
		char s2[M][M];           //定义数组 2 并用 for循环输入
		for(int j=0;j<M;j++){
			for(int k=0;k<M;k++){
				cin>>s2[j][k];
			}
		}
		
		int l1=0,l2=0;      // 用数字定义数组1的指针  
    	int k1=0,k2=0;      // 用数字定义数组2的指针
    	int d1=0,d2=0;      // 用于锚定数组1对应数组2头部的位置
    	int key=0;          // 一个记录全正确比较的值       !! 优化后可省略该参数 
		int ch=0;           // 用于判断是否更换锚点的参数 
		while(1){
    		if(ch==1){                        //设定判别参数判定锚点是否更改 
    			d1=l1;
    			d2=l2;
			}	
    		if(s1[l1][l2]==s2[k1][k2]){       //比较数组1与数组2的指针域指向的值是否相等 
    			key++;                       
				ch=0;
				l2++;                         //若相等则数组1和数组2的指针都向后移动 
    			k2++;
    			
				if(k2==M){                    //若数组2的指针溢出,则指针换行 
    				l1++;
    				l2=l2-M;                  //注意换行后数组1的指针指向,应与上一行的位置联系起来 
    				k1++;
    				k2=0;
				}
				
				if(k1==M){                    //若数组2的列指针溢出,则比较完成。 
//					cout<<"yes"<<endl;        //优化前 
					res[i] = 1;               //优化后 
					break;
				}
    		}	
    		
    		else {
    			ch = 1;
    			if(l2>0){                     //注意指针的变化情况,若在上面改变了指针应改回来再执行后续 
					l2--;
    				k2--;
				} 
    			key=0;                        // key值清零表示需从头再全部比较数组2 
    			d2++;                         //数组1与2的对应值不相等时,移动大数组的锚点指针                          
    			k2=0;
    			
    			if(d2==N-M+1){                // 若发现大数组剩下的列数小于小矩阵时可直接换行 
    				d1++;
    				d2=0;
    				k1=0;
    				k2=0;
				}
				if(d1==N-M+1){                // 若发现大数组剩下的矩阵小于小矩阵时可直接结束 
//					cout<<"No"<<endl;         // 优化前 
					res[i]=0;                 // 优化后 
					break;
				}
				l1=d1;
				l2=d2;
			} 		
		}
		i++;
	}
	cout<<"输出行数为:"<<n<<endl;
	for(int x=0;x<n;x++){
		if(res[x]==1){
			cout<<"yes"<<endl;
		}
		else cout<<"no"<<endl;
	}
	return 0;
}

优化后的输出结果

在这里插入图片描述
至此该任务也算完成啦,希望后面遇到问题能够披荆斩棘!!!
加油年轻人,冲冲冲!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值