第四章学习小结

KMP真是神奇的算法,原理是懂了,可敲代码的时候还是显得稀里糊涂的。

那就说说AI算法题吧

本题要求你实现一个简易版的 AI 英文问答程序,规则是:

  1. 无论用户说什么,首先把对方说的话在一行中原样打印出来;
  2. 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
  3. 把原文中所有大写英文字母变成小写,除了 I;
  4. 把原文中所有独立的 I 和 me 换成 you;
  5. 把原文中所有的问号 ? 换成惊叹号 !;
  6. 把原文中所有独立的 can you 换成 I can —— 这里“独立”是指被空格或标点符号分隔开的单词;
  7. 在一行中输出替换后的句子作为 AI 的回答。

输入格式:

输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。

输出格式:

按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。

 

第一反应:好长,要考虑的好多,好难。。。。。。

不过实践课上老师化整为零的讲了讲发现好像还行,自己能试试(试试就逝世)

首先对整体做一个规划,在主函数里列出大致思路

int main()
{
    string s;
    int n, i;
    cin >> n;
    getchar(); //吸收回车符 
    for (i = 1; i <= n; ++i) {
        getline(cin, s);
        cout << s<<endl;
        cout << "AI: ";
        go(s);//AI根据s输出对话 
    }
    return 0;
}

然后就是go函数了,这方面要考虑的偏多(尤其是各种越界情况)

首先考虑前面全是空格的情况,那么我们先定位到开头非空的地方

char t[3001];  //全是I时达最长长度,加三倍
    int i = 0, j;  //i,j分别为s,t的下标
    //i定位到s的第一个非空字符 
    for (; s[i] == ' '; ++i);  //循环体为空

之后就要考虑其他空格的情况,消去多余的空格

while (s[i] != '\0') {
        if (s[i] == ' ' && s[i - 1] == ' ') {
            ++i; //如果漏了这句,有连续空格时会死循环
            continue;
        }

之后是单个字符转化的问题,这方面比较简单且没什么坑

if (s[i] == '?') {
            t[j++] = '!';
            ++i;
            continue;
        }
        if (s[i] != 'I') {
            t[j++] = tolower(s[i++]);
            continue;
        }
        t[j++] = s[i++]; //s[i]='I'的情况 若为me则改成you

至于多个字符整体转化的问题,我们对输出数列进行操作,由于牵扯到j-1这样的东西,需考虑越界情况

while (t[j] != '\0') {
        if (t[j] == 'I' && (j == 0 || isSeparator(t[j - 1])) && isSeparator(t[j + 1])) {
            cout << "you";
            ++j;
            continue;
        }
        if (t[j] == 'm' && t[j + 1] == 'e' && (j == 0 || isSeparator(t[j - 1])) && isSeparator(t[j + 2])) {
            cout << "you";
            j += 2;
            continue;
        }
        if ((j == 0 || isSeparator(t[j - 1])) && 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'&&isSeparator(t[j + 7])) {
            cout << "I can";
            j += 7;
            continue;
        }
        if (t[j] == ' '&&iswhite(t[j + 1])) {
            j++;
            continue;
        }
        cout << t[j++];
    }
    cout << endl;
}

然后好像就差不多了?似乎这题也就这样了吧。。。不过自己写的时候可能思路还不会这么清晰,而且一旦出现bug就可能再也出不去了。

整体代码贴一下

#include<iostream>
#include<string>
using namespace std;

bool iswhite(char ch) {
    ch = tolower(ch);
    if ((ch >= '0' && ch <= '9') || (ch >= 'a'&&ch <= 'z')) {
        return false;
    }
    return true;
}

bool isSeparator(char ch)
{//判断ch是否分隔符
//ch可能是:数字、字母、标点、空格、\0
//分隔符:!(数字、小写字母、I)
    ch = tolower(ch);
    if (ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch == 'I')
        return false;
    else
        return true;
}

bool isSeparator1(char ch)
{
    ch = tolower(ch);
    if (ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch == 'I'||ch==' ')
        return false;
    else
        return true;
}   //若标点符号前面为空格,则删除

void go(string s)
{
    char t[3001];  //全是I时达最长长度,加三倍
    int i = 0, j;  //i,j分别为s,t的下标
    //i定位到s的第一个非空字符 
    for (; s[i] == ' '; ++i);  //循环体为空
    j = 0;     //j的初值为0
    while (s[i] != '\0') {
        if (s[i] == ' ' && s[i - 1] == ' ') {
            ++i; //如果漏了这句,有连续空格时会死循环
            continue;
        }
        if (s[i] == '?') {
            t[j++] = '!';
            ++i;
            continue;
        }
        if (s[i] != 'I') {
            t[j++] = tolower(s[i++]);
            continue;
        }
        t[j++] = s[i++]; //s[i]='I'的情况 若为me则改成you
    }
    t[j] = '\0';
    j = 0;
    while (t[j] != '\0') {
        if (t[j] == 'I' && (j == 0 || isSeparator(t[j - 1])) && isSeparator(t[j + 1])) {
            cout << "you";
            ++j;
            continue;
        }
        if (t[j] == 'm' && t[j + 1] == 'e' && (j == 0 || isSeparator(t[j - 1])) && isSeparator(t[j + 2])) {
            cout << "you";
            j += 2;
            continue;
        }
        if ((j == 0 || isSeparator(t[j - 1])) && 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'&&isSeparator(t[j + 7])) {
            cout << "I can";
            j += 7;
            continue;
        }
        if (t[j] == ' '&&iswhite(t[j + 1])) {
            j++;
            continue;
        }
        cout << t[j++];
    }
    cout << endl;
}

int main()
{
    string s;
    int n, i;
    cin >> n;
    getchar(); //吸收回车符 
    for (i = 1; i <= n; ++i) {
        getline(cin, s);
        cout << s<<endl;
        cout << "AI: ";
        go(s);//AI根据s输出对话 
    }
    return 0;
}

感觉上升了一个层次之后自己思路还是颇为混乱,有时候甚至感觉还没上个学期直接在主函数里操纵顺畅舒心。。。

上个目标基本完成吧,尽力的挤压挤呀挤时间,说实话还是自己太菜了。。。有些地方要绕许久。

下一张学到树了,也是闻名许久的东西,非常重要。希望自己能好好掌握,另外将前面的东西融会贯通,摸索出一条适合自己思维线出来。

 

posted @ 2019-04-14 22:30  我又不乱来aa  阅读(95)  评论(1编辑  收藏  举报