每日算法练习——损坏的键盘(又名:悲剧文本)(Broken Keyboard)

问题描述

在显示屏上盲打一段文字,在这过程中由于键盘的问题,Home键与end键会自动按下,显有一段文本,其中‘[’表示Home键按下,‘]’表示End键按下,求出显示屏上的文字排序

示例输入

This_is_a_[Beiju]_text

[[]][][]Happy_Birthday_to_Tsinghua_University

示例输出

BeijuThis_is_a__text

Happy_Birthday_to_Tsinghua_University

问题分析

废话:

很容易有这样的思路,找出‘[’与‘]’之间的文字将其移到文字的最前面即可,但是对于在一段文字前插入字符,每插入一个字符,在下一次插入时,其耗费的时间便越长,需要剩余文本全体想后移一位。故而,单纯的使用数组是不可取的。

借助于链表的思想,设定一个next,使得每个元素与下一个元素有一定的关联,传统意义上的链表多用指针来表示,但是在算法竞赛中,使用指针实在不是上上之选,而且也过于麻烦,因此我们这样假定:

s[ ]:输入的样本为字符数组,s[0]设为0,字符从s[1]开始输入

next[ ]:s[next[i]]=p[i+1](p[ ]:输出的样本为字符数组)  即next[i]表示s[i]的下一个

对算法竞赛入门经典中的分析:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 1000

int main()
{
    int last,cur,next[maxn];    //last记录末位置,cur指向当前位置,next[]记录输出顺序
    int i;
    char s[maxn];   //输入字符串
    while(scanf("%s",s+1)==1)      //s[0]空出
    {
        last=cur=0;
        next[0]=0;  //next[i]置0,意为不指向任何值
        
        for(i=1;i<=strlen(s+1);i++)
        {
            if(s[i]=='[') cur=0;    //当输入]时,cur光标指向首位置
            else if(s[i]==']')  cur=last;   //当输入]时,cur光标指向末尾
            else    //当读入其他字符时,插值操作
            {
                next[i]=next[cur];
                next[cur]=i;
                if(last==cur)   last=i; //当末尾值和当前光标位置相同时,last和cur一样向i跟进
                cur=i;  //尾光标向后移动 
            }
        }
        //顺次输出 
        for(i=next[0];i!=0;i=next[i])
            printf("%c",s[i]);
        printf("\n");

    }
    return 0;
}

刘汝佳一上来就把链表的核心抛出来了,我足足看了一下午。
0.为了方便起见,常常在链表第一个元素之前放一个虚拟节点s[0]
1.光标cur,最后一个字符编号last,其实只是由于这题home,end的条件限制,如果用数组建立单链表,只需要next[i]和s[i]
2.其中next[i]是s[i]连的下一个字符的编号,比如:
s[0],next[0]=3连下一个字符->
s[next[0]],next[next[0]]
3.在本题中,如果next[i]=0,说明不知道这个节点连哪个下一个节点,如果全部插入完节点,遇到next[i]=0,就意味着这个链表已经结束
所以有如下对链表遍历的方法:

        for(i=next[0];i!=0;i=next[i])
            printf("%c",s[i]);

4.下面说说如何插入
s[i]对应一个next[i],那么s[i]下一个连的是s[next[i]],next[next[i]]
如果在s[i]后面插入s[j]next[j]
只需next[j]=next[i],next[i]=j
新节点j先插到s[i]指向的s[next[i]]的前面,再把前面i的后面连的那个节点改为新插入的那个j


5.再来说说本题
a.只需改变s的输出顺序,输出s[next[i]]
b.多了个[],就是说插入的位置会发生变化。
★c.next[]数组来记录输出顺序。★

加下来使用一组输入演示过程,便于理解,需要提醒的是:下图中s是输入字符串,当输出next的下标对应的s中的字符时,下一个要输出的字符的下标的next下标,是当前next的值

(纠正,下图中是next下标,不是下表)

比如一般输入abc[def]xyz

输入a的时候next[0]=0,输入b的时候next[0]=1,next[1]=0 ,输入c的时候next[2]=next[1]=0,next[1]=i=2,以此类推

当i=4时,读到‘[’的时候,cur置0,光标指到首位,

进入下一个循环,将首位的next值提到next[i]的位置:

变成next[0]=5,next[5]=1,此时last停留在last=4;

接着继续else if循环,知道读到‘]’,此时进入if语句cur=last=4,

继续循环,将会进入else if语句将next[cur]赋值给next[i],将i赋值给next[i],如下:

继续循环直到结束,会得到以下结果:

接下来按照next[]的指示

        for(i=next[0];i!=0;i=next[i])
            printf("%c",s[i]);

next[0]=5 即输出s[5];next[next[0]=5]=6 即输出s[6];next[next[6]=7] 即输出s[7];next[next[6]=7]=1,即输出s[1];以此类推

输出:

defabcxyz

6.悟道可能时算法学习必经之路,多看就明白了

猜你喜欢

转载自blog.csdn.net/qq_41420747/article/details/81811662