残损的键盘(又名:悲剧文本)(Broken Keyboard(a.k.a Beiju Text),UVa11988)题解

偏执的太偏执、 2022-12-28 07:22 217阅读 0赞

文章目录

  • 题目描述
    • 输入
    • 输出
  • 原题(PDF)
    • 算法分析
    • 解题标程( C )
    • 解题标程(CPP)
    • 错题总结

题目描述

你在输入文章的时候,键盘上的Home键和End键出了问题,会不定时的按下。你却不知道此问题,而是专心致志地打稿子,甚至显示器都没开。当你打开显示器之后,展现你面前的数一段悲剧文本。你的任务是在显示器打开前计算出这段悲剧的文本。 给你一段按键的文本,其中’[‘表示Home键,’]‘表示End键,输入结束标志是文件结束符(EOF)。
输出一行,即这段悲剧文本。

输入包含多组数据,每组数据占一行,包含不超过100000个字母、下划线、字符”[“或者”]“。

输入

  1. This_is_a_[Beiju]_text
  2. [[\]\][][]Happy_Birthday_to_Tsinghua_University

输出

  1. BeijuThis_is_a__text
  2. Happy_Birthday_to_Tsinghua_University

原题(PDF)

在这里插入图片描述


算法分析

最简单的方法就是用数组去存储每次在首位输出的串和末尾的串,然后频繁的将尾部串strcat连接到首位串中,但是这样的算法会超时
因此我们这里采用链表
在C语言的算法中用数组来模拟链表,而CPP中可以直接使用STL中的list容器加上list迭代器解决问题
这里着重讲一下C语言的算法,用next数组去存储当前字符的下一位下标比如,next[1]=2,就意味着指向下标为2的字符,我们需要将next[0]单独拿出来作为没有数据存储的“头节点”,因此串s要的有效范围为1~n,并且用cur变量来记录光标位置,用last来记录当前的尾部位置,光标始终在s[cur]的右边。

  • 当s[i]==’[‘时,光标cur=0,光标到首部
  • 当s[i]==’]‘时,光标cur=last,光标到末尾
  • 当s[i]为字符时,根据光标的位置(模拟尾插法)next[i]=next[cur];next[cur]=i 然后让光标等于i,去处理下一个i,如果尾部和光标位置相同意味着最近的控制字符为’]’,则尾部也同样移向i的位置。

解题标程( C )

  1. #include <stdio.h>
  2. using namespace std;
  3. #define maxl 100005
  4. int main()
  5. {
  6. char s[maxl];
  7. while(~scanf("%s",s+1))
  8. {
  9. int Next[maxl]={
  10. 0};
  11. int cur=0,last=0;
  12. for (int i = 1; s[i]; ++i)
  13. {
  14. if(s[i]=='[') cur=0;
  15. else if(s[i]==']') cur=last; //last会停止在[的左边一个字符,让光标cur回到last来继续链接
  16. else
  17. {
  18. //链表插入操作(就类似于尾插法)
  19. Next[i]=Next[cur]; //(令i的后续等于cur的后续,i始终是大于cur的)(类似于p->next=l->next)
  20. Next[cur]=i; //(令cur的后续等于i)(类似与l->next=p)
  21. //last的更新
  22. if(cur==last) last=i;
  23. //cur的更新
  24. cur=i;
  25. }
  26. }
  27. for (int i = Next[0]; i != 0; i = Next[i])
  28. if (s[i]!='['&&s[i]!=']')
  29. printf("%c",s[i]);
  30. printf("\n");
  31. }
  32. return 0;
  33. }

解题标程(CPP)

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <list>
  4. #include <iostream>
  5. using namespace std;
  6. int main()
  7. {
  8. char str[100005];
  9. list <char> s;
  10. while (scanf("%s",str)!=EOF)
  11. {
  12. list <char>::iterator it=s.begin();
  13. int n=strlen(str);
  14. for (int i=0;i<n;i++)
  15. {
  16. char ch=str[i];
  17. if (ch=='[') it=s.begin();
  18. else if(ch==']') it=s.end();
  19. else
  20. {
  21. it=s.insert(it,ch);
  22. it++;
  23. }
  24. }
  25. for (it=s.begin();it!=s.end();it++)
  26. printf("%c",*it);
  27. s.clear();
  28. printf("\n");
  29. }
  30. return 0;
  31. }

错题总结

  • 在数组中频繁移动元素是很低效的,如有可能,可以使用链表

发表评论

表情:
评论列表 (有 0 条评论,217人围观)

还没有评论,来说两句吧...

相关阅读

    相关 程序员爱情悲剧

    刚才无意间翻到了我三年前发的一篇文章“别了大学”,三年前还没上csdn,不然当时就发到这里了,唉三年多了,大大小小的挫折也经历了不少,但自己终归 还是抗了过来。呵呵~现在再看这