19084 万万没想 到之聪明的编辑

字节跳动2019春招研发部分编程题汇

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

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

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

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

输入格式

第一行包括一个数字N,表示本次用例包括多少个待校验的字符串。1<=N<=50

后面跟随N行,每行为一个待校验的字符串。字符串长度不超过1000

输出格式

N行,每行包括一个被修复后的字符串。

输入样例

2
helloo
wooooooow

输出样例

hello
woow

解题思路:典型的签到题,因为数据规模决定了使用任何方法都能通过。这里介绍三种复杂度O(n)作法。

(一)单链表作法

题目中要求消除(删除)元素,未避免删除后移动元素,用链式结构是一种较好的选择。

int i,j,t,n,nex[10005]= {0};
    char c[10005]= {0};
    cin>>t;
    while(t--)
    {
        scanf("%s",c+1);/**< 从下标1开始读取 */
        n=strlen(c+1);
        for(i=1; i<n; i++) /**< 构造静态链表*/
            nex[i]=i+1;
        nex[n]=0;/**< 尾结点指针为0 */
        int c1=1,c2,c3,c4;/**< 定义4个指针来处理问题,依次相邻四个字符 */
        while(c1)
        {
            c2=nex[c1],c3=nex[c2],c4=nex[c3];/**<满足AAA或AABB删除  */
            if(c2&&c[c1]==c[c2]&&( (c3&&c[c2]==c[c3]) || (c4&&c[c3]==c[c4])  ))
                nex[c2]=c4;/**< 注意判定条件时一定要确保指针c2,c3,c4不是0,即非空指针 */
            else
                c1=c2;
        }
        c1=1;
        while(c1)
        {
            cout<<c[c1];
            c1=nex[c1];
        }
        cout<<endl;
    }
    return 0;

(二)栈结构消除

字符串消除问题,可考虑能不能用栈结构解决。用栈存储字符串,i为当前处理字符,如果栈顶两个元素为AA,i也是A或者i和i+1为BB时,i不需要入栈,其他情况i都必须入栈。

标准栈结构只能得到栈顶一个元素,无法解决AA判定,因此必须手写栈结构。

int i,j,t,n,top=0;
    char c[10005]= {0},st[1005];/**< 手写一个栈结构st,top为栈顶指针 */
    cin>>t;
    while(t--)
    {
        scanf("%s",c+1);/**< 从下标1开始读取 */
        n=strlen(c+1);
        top=0;
        for(i=1;i<=n;i++)
        {
            if(top>=2) /**< 栈中多于2个元素才能判断 */
            {
                if(st[top-1]==st[top-2]&&(c[i]==st[top-1]||c[i]==c[i+1]))/**< 满足AAA或AABB相等条件 */
                  continue;
            }
            st[top++]=c[i];
        }
        for(i=0;i<top;i++)/**< 输出栈中所有元素 */
            cout<<st[i];
        cout<<endl;
    }
    return 0;

(3)枚举算法

枚举每一个字符i,看看是否需要删除。思考一下,当字符i的左侧为AA情况时,有三种可能AAA,AABB,AABC,前两种可以认为i被删除,继续查看i+1就行了。当出现AABC????这种情况时,下一次判定不用再管AAB了(不可能参与消除),看看C和C后面是否相同,继续向后扫描

int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i=2,j,p1=1,p2=0,t;
    cin>>t;
    while(t--)
    {
        i=2,p1=1,p2=0;
        string s;
        cin>>s;
        while(i<s.size())
        {
            if(s[p1]!=s[p2]) /**< 先找到AA情况 */
            {
                p1++,p2++,i++;
                continue;
            } /**< 如果s[i]能凑成AAA或AABB,把s[i]清除,继续向后检查 */
            while(s[i]==s[p1]||s[i]==s[i+1])
                s[i++]=' ';/**< 用空格字符实现清除 */
            p2=i+1,p1=i+2,i+=3;/**< 一定是AABC情况,下一次让p2指向c */
        }
        for(i=0; i<s.size(); i++)
            if(s[i]!=' ')
                cout<<s[i];
        cout<<endl;
    }
    return 0;
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值