损坏的键盘(又名:悲剧文本)(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.悟道可能时算法学习必经之路,多看就明白了
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号