在另一篇文章XDOJ.T204_单词统计(超强算法)中介绍了有穷自动机的基本用法后,再来灵活运用一下。比如这一道题。
标题
字符串查找
类别
字符串处理
时间限制
2S
内存限制
256Kb
问题描述
给出一个字符串和多行文字,输出在这些文字中出现了指定字符串的行。
程序还需要支持大小写敏感选项:
当选项打开时,表示同一个字母的大写和小写看作不同的字符;
当选项关闭时,表示同一个字母的大写和小写看作相同的字符。
输入说明
输入数据第一行包含一个字符串s,由大小写英文字母组成,长度不超过100。
第二行包含一个数字,表示大小写敏感选项。当数字为0时表示大小写不敏感,当数字为1时表示大小写敏感。
第三行包含一个整数n,表示给出的文字行数。(并没有指定n的取值范围,只好假设n<=100,还好能得满分)
接下来n行,每行包含一个字符串,字符串由大小写英文字母组成,不含空格和其他字符。
每个字符串长度不超过100。
输出说明
输出多行,每行包含一个字符串,按出现的顺序依次给出那些包含了字符串s的行。
输入样例
Hello
1
5
HelloWorld
HiHiHelloHiHi
GrepIsAGreatTool
HELLO
HELLOisNOTHello
输出样例
HelloWorld
HiHiHelloHiHi
HELLOisNOTHello
对于这一题而言,只有两种状态
- 不是要查找的单词的对应字母(LETTER)
- 当前字母正是要查找的单词的对应字母,而且第n个字母的状态就用n表示(WORD,。。。)
#include <stdio.h>
#include <string.h>
#define WORD 1
#define LETTER -1
int main()
{
char word[101];
gets(word);
int sensi; //sensitivity(敏感),这正是此题的特殊之处之一
int n;
scanf("%d%d",&sensi,&n);
getchar();
if(!sensi)strupr(word); //若sensi等于0,则大小写不敏感,把字符数组word中的字符全部转变为大写
char str[101][101],str1[101]; /*字符数组str1的存在是为了保证字符数组str的内容不变
因为最后输出的必须是原字符串*/
int i=0,j;
for(;i<n;++i)
{
gets(str[i]);
}
int state=LETTER;
int len=strlen(word);
for(i=0;i<n;++i)
{
strcpy(str1,str[i]);
if(!sensi)
{
strupr(str1); //如果大小写不敏感,那么这样做能避免改变字符数组str的内容
}
int done=0; /*这也是此题的特殊之处之一,不需要统计单词出现了多少次,只需要根据情况输出这一行字符串,
done用于判断这一行字符串是否已经被输出*/
for(j=0;str1[j];++j)
{
// printf("J:%d STATE:%d\n",j,state);
switch(state)
{
case(LETTER):
if(str1[j]==word[0])state=WORD;
break;
default:
if(state<len)
{
if(str1[j]==word[state])++state;
else
{
j-=state; /*这也是此题的特殊之处之一
对于某些特殊样例,必须这样做*/
state=LETTER; //状态不要忘记改变
}
}
else if(state==len)
{
printf("%s\n",str[i]); //如果大小写不敏感,那么字符数组str1中的字母全为大写,因此应该输出str[i]
done=1;
state=LETTER;
}
}
if(done)break; //如果这一行字符串是否已经被输出,那么done等于1,break,不需要再管剩下的字符
}
if(state==len&&!done) //如果这一行字符串是否已经被输出,那么done等于1,不需要再输出
{
printf("%s\n",str[i]);
state=LETTER;
}
}
return 0;
}
除了状态只有两种以外,本题还有很多特殊之处:
- 程序还需要支持大小写敏感选项:当选项打开时,表示同一个字母的大写和小写看作不同的字符;当选项关闭时,表示同一个字母的大写和小写看作相同的字符。为了保证输出结果的正确,另定义了字符数组str1
- 需要输入的字符串有多行,因此定义了一个二维字符数组str
- 需要输出的不是单词出现的次数,而是含有被查找单词的字符串,变量done可以避免在某些情况下的重复输出
- 至于j-=state,对于某些特殊情况必须这样做。比如这样的输入样例:
HeHeh
1
1
HeHeHeheH
如果不加上“j-=state;”这条语句,当程序检查到“HeHeHeheH”中的第三个‘H’时state变为LETTER,下一个循环之前j自增1,然后程序开始检查第三个‘e’,最后你会发现没有输出。
当然了,这题很可能有更简单的算法甚至思路。如果大佬们有,鄙人定当洗耳恭听。