第四章学习小结

KMP算法

刚开始接触KMP算法时,我几乎完全没看懂,但是在阅读了几篇关于KMP的详解文章后,虽然没有完全掌握KMP算法,但是已经可以理解它的原理还有实现方法了。

我认为KMP最难理解的地方是当模式串某一个字符与主串不匹配时,我们将j指针要移动到哪?从下图可以看出来,j要移动的下一个位置k,最前面的k个字符和j之前的最后k个字符是一样的。

因为在P的每一个位置都可能发生不匹配,也就是说我们要计算每一个位置j对应的k,所以用一个数组next来保存,next[j] = k,表示当T[i] != P[j](T为主串,P为模式串)时,j指针的下一个位置。

 

  

在这里附上代码,虽然最后还是有一点错误,可能还是存在缺陷,但是对于理解KMP算法我已经尽力了。。。

#include<iostream>
using namespace std;
void get_next(char * s,int * next)//next函数的实现
{
int i=0; //next数组的下标
int j=-1; //next
next[0]=-1;
while(s[i]!='\0')
{
if(j==-1 || s[i]==s[j]) //如果不存在或这条件符合了,那么就可以得到next值了
{
++i;++j;
next[i]=j;
}
else{
j=next[j];
}
}
}

int KMP(char * s,char * t,int pos)//KMP算法的实现
{
int j=0;
while(t[j++]!='\0');
int * next=new int[j-1];

int length=j-1; //串的长度
get_next(t,next);//调用函数,生成对应的next值

int i=pos-1;//主串的起始位置
j=0;//模式串的下标
while(s[i]!='\0' && j<length)
{
if(j==-1 || s[i]==t[j]) //考虑到第一个不相等的情况
{
++i;++j;
}
else
{
j=next[j]; //如果不相等,则从next值开始下一次比较(模式串的右移)
}
}

if(t[j]=='\0' && j!=-1)
{
return i-j+1;
}
else
{
return 0;
}
}
int main()
{
    char s[1000000];
    char t[100000];
    cin>>s;
    cin>>t;
    int a=KMP(s,t,1);
    cout<<a;
    return 0;
}

 

 

AI核心代码

在老师讲过AI的题目后,原本一筹莫展的问题就没有那么困难了,经过一次次尝试和改进之后,我终于做对了这道题。下面展示过程。

首先第一次尝试的时候,我的main函数写得很复杂,而且getchar函数的用法也是错误的,导致我虽然输入了相应的行数及字符,但是字符串在存储的时候还是存在问题。在改正了问题之后,我发现,虽然它正常地输出了字符串,但是输出字符串之后才进行了字符串的处理,后处理的字符串又重新被输出了。我意识到了问题的所在,于是,我便将main函数中的其他功能的实现过程全部整合在另一个函数中,在主函数中调用该函数,使得代码显得简洁一些,并且改正了问题。

                

下面是主函数,实现输入输出,在主函数中调用go()函数,用go()函数实现AI功能。

int main()
{
    int n; 
    string s;
    char a; 
    cin>>n;
    int i,j=0;
    a=getchar();
    for(i=1;i<=n;i++)
    {
        getline(cin,s);
        cout<<s<<endl;
        cout<<"AI: ";
        go(s);
    }
    return 0;
}

 

 

下面是主要功能的实现。

void go(string s)
{
    string t;    //t为处理后的字符串 
    int i=0;
    int j=0;        //i定位到s的第一个非空字符,j表示t串的字符
    for(i=0;s[i]!='\0'&&isSpace(s[i]);++i);//定位到s的第一个非空格字符 
    while (s[i] != '\0') //进行输入
    {    
        if (s[i] == ' '&&s[i - 1] == ' ') //跳过多余的空格
        {        
            i++;
            continue;
        }
        if (s[i] == '?') //将输入的问号变为感叹号
        {        
            t[j] = '!';
            i++;
            j++;
            continue;
        }

        if (s[i] != 'I') //将除了I的大写变小写
        {        
            t[j] = tolower(s[i]);
            i++;
            j++;
        }
        else //将s串的非空或者单个空格给到t串,之后分别+1进行下一轮输入
        {
            t[j] = s[i];    
            j++;
            i++;
        }
    }
    t[j] = '\0';//为t串末尾增加结尾符
    

    //I,me变成you
    j = 0;
    while (t[j] != '\0') {
        //独立的I,意味着左右均是分隔符
        if (t[j] == 'I'&&(j==0||isAlone(t[j - 1])) && isAlone(t[j + 1])) 
        {            
            cout << "you";
            j++;
            continue;
        }
        //独立的me
        if (t[j] == 'm'&&t[j + 1] == 'e'&& (j == 0 || isAlone(t[j - 1])) && isAlone(t[j + 2])) 
        {    
            cout << "you";
            j += 2;
            continue;
        }

        if ((t[j]=='c'&&t[j+1]=='a'&&t[j+2]=='n'&&t[j+3]==' ' &&t[j+4]=='y'&&t[j+5]=='o'&&t[j+6]=='u')&&(j==0||isAlone(t[j-1])&&isAlone(t[j+7]))) //独立的can you
        {
            cout << "I can";
            j += 7;
            continue;
        }

        
        if (t[j] == ' '&&isAlone(t[j+1])) //如果是标点前的空格就不输出
        {
            j++;
            continue;
        }
        cout << t[j];
        j++;
    }
    cout << endl;
}

bool isSpace(char c)//判断是否为空格 
{
    return c==' ';
}

 

这里学到一种处理方式,tolower是一种函数,功能是把字母字符转换成小写,非字母字符不做出处理。

bool isAlone(char c)//判断是否为独立的字符 
{
  c=tolower(c);
  if(!(c>='0'&&c<='9'||c>='a'&&c<='z'))
  return true;
  else return false;
}

目标完成情况

上一次的目标是继续巩固和学习栈和队列,争取在做像银行业务那样的题目时,首先想到的不是数组,而是如何用队列解决问题,在使用队列时,不再发生思维混乱的情况。课后我将多多阅读相关材料,多阅读借鉴他人的博客,完善自己的不足之处。

在课后,我阅读了相关的资料还有博客,对于栈和队列加深了理解,但是还是没有做到熟练掌握,可能在做题的时候还是不能首先想到使用栈和队列来解决问题。所以接下来还是要继续巩固所学知识,多多练习。

 

posted @ 2019-04-14 16:37  带我去喝冰可乐  阅读(164)  评论(2编辑  收藏  举报