zoukankan      html  css  js  c++  java
  • 字节跳动笔试题——万万没想到之聪明的编辑

    转载请注明链接,有问题请及时联系博主:Alliswell_WP

    题目描述:

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32M,其他语言64M


    我叫王大锤,是一家出版社的编辑。我负责校对投稿来的英文稿件,这份工作非常烦人,因为每天都要去修正无数的拼写错误。但是,优秀的人总能在平凡的工作中发现真理。我发现一个发现拼写错误的捷径:

    1. 三个同样的字母连在一起,一定是拼写错误,去掉一个的就好啦:比如 helllo -> hello
    2. 两对一样的字母(AABB型)连在一起,一定是拼写错误,去掉第二对的一个字母就好啦:比如 helloo -> hello
    3. 上面的规则优先“从左到右”匹配,即如果是AABBCC,虽然AABB和BBCC都是错误拼写,应该优先考虑修复AABB,结果为AABCC

    我特喵是个天才!我在蓝翔学过挖掘机和程序设计,按照这个原理写了一个自动校对器,工作效率从此起飞。用不了多久,我就会出任CEO,当上董事长,迎娶白富美,走上人生巅峰,想想都有点小激动呢!
    ……
    万万没想到,我被开除了,临走时老板对我说: “做人做事要兢兢业业、勤勤恳恳、本本分分,人要是行,干一行行一行。一行行行行行;要是不行,干一行不行一行,一行不行行行不行。” 我现在整个人红红火火恍恍惚惚的……


    请听题:请实现大锤的自动校对程序

    输入描述:
    第一行包括一个数字N,表示本次用例包括多少个待校验的字符串。
    后面跟随N行,每行为一个待校验的字符串。

    输出描述:
    N行,每行包括一个被修复后的字符串。

    输入例子1:
    2
    helloo
    wooooooow
    
    输出例子1:
    hello
    woow

    >vi main.c

    #define _CRT_SECURE_NO_WARNINGS
    #include<iostream>
    #include<string>
    #include <algorithm>
    
    using namespace std;
    
    // 初始化,获取数据
    int  getFileContent(char *pFileName/*in*/, char ***p, int *nLine)
    {
        cout << "请输入待检测的行数N: " << endl;
        cin >> *nLine;
        cout << "请依次输入待检测的数据: " << endl;
        getchar();
        char **tmpP = NULL;
        tmpP = (char **)malloc(sizeof(char *) * *nLine);
        if (tmpP == NULL)
        {
            cout << "func getFileContent() err: " << endl;
            return -1;
        }
    
        // 依次输入n行内容
        for (int i = 0; i < *nLine; i++)
        {
            tmpP[i] = (char *)malloc(20);
            cin.getline(tmpP[i], 20);
        }
    
        //间接赋值
        *p = tmpP;  
        return 0;
    }
    
    int  getFileContent_Free(char **p, int iLine)
    {
        int i = 0;
        if (p == NULL)
        {
            return 0;
        }
    
        for (i = 0; i < iLine; i++)
        {
            free(p[i]);
        }
    
        free(p);
        //p = NULL;
    
        return 0;
    }
    
    
    // 既可以把指针所指向的内存空间给释放掉 并且把实参重新赋值成NULL
    int  getFileContent_Free2(char ***p, int iLine)
    {
        getFileContent_Free(*p, iLine);
        *p = NULL;
        return 0;
    }
    
    // 依次检测每行
    int checkFileContent(char **p, int iLine)
    {
        if ((p == NULL)&&(iLine == 0))
        {
            return -1;
        }
        for (int i = 0; i < iLine; i++)
        {
            string sString = p[i];
            transform(sString.begin(), sString.end(), sString.begin(), ::tolower);
            string sonString;
            // 规则:检测小写字母
            for (int j = 0; j < 26; j++)
            {
                char ch = (char)(j + 'a');
                sonString.clear();
                // 规则1:检测3个相邻的字母
                sonString.append(3, ch);
                int pos = sString.find(sonString);
                // 找到
                while (pos != -1)
                {
                    sString.erase(pos, 1);
                    pos = sString.find(sonString, pos);
                    strcpy(p[i], sString.c_str());
                }
                // 规则2:检测aabb相邻的字母
                sonString.clear();
                sonString.append(2, ch);
                for (int k = 0; k < 26; k++)
                {
                    char ch2 = (char)(k + 'a');
                    sonString.erase(2, 2);
                    sonString.append(2, ch2);
                    int pos2 = sString.find(sonString);
                    // 找到
                    while (pos2 != -1)
                    {
                        sString.erase(pos2+2, 1);
                        pos2 = sString.find(sonString, pos2);
                        strcpy(p[i], sString.c_str());
                        break;
                    }
                }
            }
        }
    
    
        return 0;
    }
    
    // 依次打印每行
    void printFileContend(char **p, int iLine)
    {
        for (int i = 0; i < iLine; i++)
        {
            cout << p[i] << endl;
        }
    }
    
    
    int main()
    {
        int        ret = 0, i = 0;
        char    *myFileName = NULL;
        char    **myP = NULL;
        int        myLine = 0;
    
        cout << "程序开始..." << endl;
        //获取文件内容
        ret = getFileContent(myFileName, &myP, &myLine);
        if (ret != 0)
        {
            cout << "func getFileContent() err" << endl;
            return ret;
        }
    
        // 依次检测每行
        ret = checkFileContent(myP, myLine);
        if (ret != 0)
        {
            cout << "func getFileContent() err" << endl;
            return ret;
        }
    
        //打印文件内容 按照行
        printFileContend(myP, myLine);
    
        getFileContent_Free2(&myP, myLine);
    
        system("pause");
        return 0;
    }

    编程问题总结:

    1)动态分配内存?如何输入n行字符串?

    思路:用数组先整体分配空间(存储结点),然后为每行的每个变量再分配空间,指向每行字符串的首地址的位置。

    注意:释放内存的时候,顺序相反,先释放每行字符串的首地址指向的空间,后释放存储结点。


    C++的istream中的类(如cin)提供了一些面向行的类成员函数:getline()和get()。这两个函数都读取一行输入,直到到达换行符。然而,随后getline()将丢弃换行符,而get()将换行符保留在输入队列中。
    (1)getline()
    getline()函数读取整行,它使用通过回车键输入的换行符来确定输入结尾。要调用这种方法,可以使用cin.getline()。该函数有两个参数。第一个参数是用来存储输入行的数组名称,第二个参数是要读取的字符数。如果这个参数为20,则函数最多读取19个字符,余下的空间用于存储自动在结尾处添加的空字符。getline()成员函数在读取指定数目的字符或遇到换行符时停止读取。

    例如:假设要使用getline()将姓名读入到一个包含20个元素的name数组中,可以用这样的函数调用:
    cin.getline(name,20);
    这将一行读入到name数组中——如果这行包含的字符不超过19个。
    getline()函数每次读取一行。它通过换行符来确定行尾,但不保存换行符。相反,在存储字符串时,它用空字符来替换换行符。


    (2)get()
    istream类有另一个名为get()的成员函数,该函数有几种变体。其中一种变体的工作方式与getline()类似,它们接受的参数相同,解释参数的方式也相同,并且都读取到行尾。但get()并不再读取并丢弃换行符,而是将其留在输入队列中。假设连续两次调用get():

        cin.get(name,ArSize);
        cin.get(name,ArSize);    //a problem

    由于第一次调用后,换行符将留在输入队列中,因此第二次调用时看到的第一个 字符便是换行符。因此get()认为已经到达行尾,而没有发现任何可读取的内容。如果不借助于帮助,get()将不能跨过该换行符。
    get()有另一种变体。使用不带任何参数的cin.get()调用可读取下一个字符(即使是换行符),因此可以用它来处理换行符,为读取下一行输入做准备:

        cin.get(name,ArSize);   //read first line
        cin.get();              //read newline
        cin.get(name,ArSize);   //read second line

    get()相比于getline()可以使得输入更仔细。例如,假设用get()将一行读入数组。如何知道停止原因是由于已经读取了整行,而不是由于数组已经填满了呢?查看下一个字符,如果是换行符,说明已经读取了整行;否则,说明该行中还有其他输入。

    getline()使用起来简单一些,但get()使得检查错误更简单些。


    2)函数设计,如何使代码分块更好处理?

        // 获取数据内容
        getFileContent();
    
        // 依次检测每行
        checkFileContent();
    
        //打印文件内容 按照行
        printFileContend();
        
        // 释放内存
        getFileContent_Free();

    3)C/C++如何整行读入字符串?

    方法一:scanf()读入char[]

    使用方法:

    char str[1024];
    scanf("%[^
    ]",&str);
    getchar();

    说明:在scanf函数中,可以使用%c来读取一个字符,使用%s读取一个字符串, 但是读取字符串时不忽略空格,读字符串时忽略开始的空格,并且读到空格为止,因此只能读取一个单词,而不是整行字符串。

    其实scanf函数也可完成这样的功能,而且还更强大。这里主要介绍一个参数,%[ ],这个参数的意义是读入一个字符集合。[ ]是个集合的标志,因此%[ ]特指读入此集合所限定的那些字符,比如%[A-Z]是输入大写字母,一旦遇到不在此集合的字符便停止。如果集合的第一个字符是"^",这说明读取不在"^"后面集合的字符,既遇到"^"后面集合的字符便停止。注意此时读入的字符串是可以含有空格的,而且会把开头的空格也读进来。

    注意:如果要循环的多次从屏幕上读取一行的话,就要在读取一行后,在用%c读取一个字符,将输入缓冲区中的换行符给读出来。否则的话,在下一次读取一行的时候,第一个就遇到' ',匹配不成功就直接返回了。这里可以用scanf()或者getchar()函数读取换行符。

    方法二:getchar()读入char[]

    使用方法:

    char str[1024];
    int i=0;
    while((str[i]=getchar())!='
    ')
        i++;
    getchar();

    说明:这样一个一个读也可以,也会把开头的空格读进来。最后也需要考虑换行符,使用getchar()读出来。

    方法三:gets()读入char[]

    使用方法:

    char str[1024];
    gets(str);

    说明:感觉这个就是多个getchar的集合函数,很好用。功能是从标准输入键盘上读入一个完整的行(从标准输入读,一直读到遇到换行符),把读到的内容存入括号中指定的字符数组里,并用空字符''取代行尾的换行符' '。读入时不需要考虑换行符。

    方法四:getline()读入string或char[]

    使用方法:

    string str;
    getline(cin,str);//读入string
    
    char str2[1024];
    cin.getline(str2,1024);//读入char数组

    说明:这是比较常用的方法,cin.getline第三个参数表示间隔符,默认为换行符' '。读入不需要考虑最后的换行符。

    方法五:get()读入char[]

    使用方法:

    char str3[1024];
    cin.get(str3,1024);//读入char数组

    说明:get函数读入时需要考虑最后的换行符,也就是说,如果用get读入多行数据,要把' '另外读出来,一般使用cin.get(str,1024).get();来读入多组数据。

    参考——https://www.cnblogs.com/AlvinZH/p/6798023.html

    4)每次输入3后,但只能输入两行数据?

    思路:读取了之前在缓冲区中的换行符(“ ”),所以读取之前先getchar();把缓冲区中的数据清空。

    5)如何实现依次检测每行,实现规则1,实现查找相同3个字母的字符串?

    思路:先实现子串“aaa”的子串在字符串的查找,然后实现字符‘a’到‘z’的遍历,拼接完成子串的过程,然后遍历在(每行的)字符串中查找。

    6)c++ 如何获取输出26个字母?

    #include <iostream>
    using namespace std;
    void main()
    {
    int i;
    cout<<"输出小写字母:";
    for (i=0;i<26;i++)
    cout << (char) (i+'a'); //小写
    cout << endl;
    cout<<"输出大写字母:";
    for (i=0;i<26;i++)
    cout << (char) (i+'A'); // 大写
    cout << endl;
    }

    7)如何实现依次检测每行,实现规则2,实现查找AABBCC得到AABCC?

    思路:先实现子串“aaa”的子串在字符串的查找,然后实现字符‘a’到‘z’的遍历,拼接完成子串的过程,然后遍历在(每行的)字符串中查找。

    8)如果输入的字符串中有大小写,大小写字母如何处理?

    思路:由于大写字母AAa或AABBcc,这样的存在,为避免出错,所以统一使用C++自带的算法(transform(s.begin(), s.end(), s.begin(), ::tolower);),转为小写。

    注意:添加头文件#include<algorithm>

    9)c++ strcpy放到程序中报错?

    思路:这段代码放到VS2015没有问题,但是在自测程序报错,查了资料,添加头文件#include<cstring>

    转载请注明链接,有问题请及时联系博主:Alliswell_WP

  • 相关阅读:
    Java基础其他
    java网络编程
    java多线程编程
    正则表达式--位置匹配和组
    设计模式
    深入 Java Web
    mysql 好用的sql语句
    spring boot 发送邮件
    dubbo的spi机制
    原理分析dubbo分布式应用中使用zipkin做链路追踪
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/InternetCompanyProgrammingQuestions_zijietiaodong01.html
Copyright © 2011-2022 走看看