基于字符串模式匹配算法的病毒感染检测问题

639 阅读2分钟

和普通匹配不太一样的主要是人的DNA序列是环状的,所以可以把人的DNA序列,也就是主串T复制扩大一倍再和病毒DNA进行匹配。

这道题本身没什么难的,自己耗了点时间主要是在输入上……太久没写字符串相关了,顺便复习了下scanf,自己写了点遗忘的要点放在了末尾。

输入要求:多组数据,每组数据有1行,为序列A和B,A对应病毒的DNA序列, B对应人的DNA序列。A和B都为‘0’时输入结束。
输出要求:对于每组数据输出1行,若患者感染了病毒输出“YES”,否则输 出“NO”。

  • 头文件

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define MAXSIZE 50
    struct String{//由于每次求长度太麻烦所以我声明了一个带长度的结构
    	char string[MAXSIZE];
    	int size;//存储字符串长度
    };
    
  • 计算nextval数组

    void getNextval(String T, int* nextval) {
    	int i, j;
    	i = 1;
    	j = 0;
    	nextval[1] = 0;
    	while (i < T.size) {
    		if (j == 0 || T.string[i-1] == T.string[j-1]) {
    			++i;
    			++j;
    			if (T.string[i-1] != T.string[j-1])		
    				nextval[i] = j;
    			else            
    				nextval[i] = nextval[j];
    		}
    		else  
    			j = nextval[j];
    	}
    }
    
  • KMP模式匹配

    int indexKmp(String S,String T) {
    	int i = 1;
    	int j = 1;
    	int nextval[MAXSIZE];
    	getNextval(T, nextval);
    	while (i <= S.size && j <= T.size) {
    		if (j == 0 || S.string[i-1] == T.string[j-1]) {//当两字母相等时继续
    			++i;
    			++j;
    		}
    		else {
    			j = nextval[j];//j回到合适位置,i不变
    		}
    	}
    	if (j > T.size)
    		return i - T.size;
    	
    	return -1;
    }
    
  • 扩大人DNA序列

    void doubleString(String *B) {
    	for (int i = B->size , j = 0; j < B->size; i++, j++)
    		B->string[i] = B->string[j];
    	B->size *= 2;
    	return;
    }//将人DNA串扩大
    
  • 主函数

    int main() {
    	String B[MAXSIZE];//存储人的DNA序列
    	String A[MAXSIZE];//存储病毒的DNA序列
    	bool outcome[MAXSIZE];//存储匹配的结果
    	int i = 0;
    
    	scanf_s("%s", A[0].string,MAXSIZE);
    	scanf_s("%s", B[0].string,MAXSIZE);
    	A[0].size = strlen(A[0].string);
    	B[0].size = strlen(B[0].string);
    	doubleString(&B[0]);
    
    	while (A[i].string[0] != '0' && B[i].string[0] != '0') {
    		if (indexKmp(B[i], A[i])!=-1)		
    			outcome[i] = true;
    		else		outcome[i] = false;
    		i++;
    		scanf_s("%s", A[i].string,MAXSIZE);
    		scanf_s("%s", B[i].string,MAXSIZE);
    		A[i].size = strlen(A[i].string);
    		B[i].size = strlen(B[i].string);
    		doubleString(&B[i]);
    	}
    
    	for (int n = 0; n < i; n++) {
    		if (outcome[n])
    			printf("YES\n");
    		else
    			printf("NO\n");
    	}
    
    	return 0;
    }
    

总结复习

  • scanf在遇到第一个空白就不再读取输入,其在读取输入时就会把空字符放在字符串末尾。