P1308 [NOIP2011 普及组] 统计单词数

P1308 [NOIP2011 普及组] 统计单词数

个人解题思路:

问题一:如何不区分大小写地遍历

解决方案:使用transform函数来转换为小写形式。

      transform(s1.begin(),s1.end(),s1.begin(),::tolower);

      transform(s2.begin(),s2.end(),s2.begin(),::tolower);

问题二:找出第一次出现的位置和出现位置。

解决方案:使用find函数,匹配上之后判断是否是单词。如果只是单词的一部分,则往后继续搜索,直到正确匹配,第一次匹配特判记录位置。然后不断后移计数。

while((ans=s2.find(s1,ans+len))!=string::npos)

      {

            if(ans==0&&s2[ans+len]==' '||s2[ans-1]==' '&&s2[ans+len]==' ')

            {

                  if(cnt==0)

                        pos=ans;

                  cnt++;

            }

      }

此段代码可以用于单词的匹配,但是时间复杂度可能较高

洛谷题解启示

  • 自动机的概念

那么这是一道简单的有穷自动机,运行时分两种情况:

①是空格

②是字母

(其实当前状态就是上一个字符的状态)那么在遍历数组的时候拿一个变量记录下来当前是什么状态,可以用0代表当前是空格状态,1代表是字母状态

当如果当前状态是1,而现在却遇到空格,那么就计数器加一,同时要将状态改为0,如果当前状态是00,现在的字符却是字母,就只将状态改为1

    for(i = 0; a[i]; i ++ ) {//遍历数组

        switch ( state ) {

            case SPACE : //如果当前状态(上一个)是空格

                if(a[i] == word[0]) state = WORD;//变成单词第一个字母状态

                else if(a[i] == ' ') state = SPACE;//其实这句话可以省略,因为反正都是空格状态,改它是一样的

                else state = LETTER;//剩下的肯定是其他字母状态了

                break;

            case LETTER : //是其他字母状态

                if(a[i] == ' ') state = SPACE;//空格状态

                break;

            default: //是要查找的单词状态

                if ( state < len  ) {//还不是最后一个字母

                    if(a[i] == ' ') state = SPACE;

                    else if(a[i] == word[state]) state ++ ;//变成下一个字母状态

                    else state = LETTER;//其他字母状态

                }

                else if (state == len )//是最后一个字母

                {

                    if(a[i] == ' ') {//如果下一个是空格,找到了!

                        state = SPACE;//状态不要忘记改变

                            if(ans2 == -1)//第一次找到,记录下来位置

                                ans2 = i - len;//因为i是单词的尾,所以要减长度

                        ans ++ ;//个数加一

                    }

                    else state = LETTER;//可惜,最后跟着其他字母,不是单词

                }

        }

    }

源自wxy_god

不断地遍历数组,每次记录状态,根据不同状态进行分类进行下一步运算,时间复杂度低。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值