XDOJ.T81_字符串查找

在另一篇文章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 
#include 

#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’,最后你会发现没有输出。
当然了,这题很可能有更简单的算法甚至思路。如果大佬们有,鄙人定当洗耳恭听。

你可能感兴趣的:(#,XDOJ,“难题”集萃)