UVa11988 Broken Keyboard(悲剧文本)
题目链接:UVa11988
题目描述:
输入包含多组数据,每组数据占一行,包含不超过100000个字母、下划线、字符“[”或者“]”。其中字符“[”表示Home键,“]”表示End键。输入结束标志为文件结束符(EOF)输入文件不超过5MB,对于每组数据,输出一行,即屏幕上的悲剧文本
样例输入:
This_is_a_[Beiju]_text
[[]][]Happy_Birthday_to_Tsinghua_University
样例输出:
BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University
题目分析:
最简单的思路就是用数组来保存这段文本,之后用一个变量pos保存“光标位置”,这样输入一个字符相当于在数组中插入一个字符,这样就需要先把后面的字符全部右移,给新的字符填出位置
由上面分析,我们可以知道,这样就非常复杂了,会超时间
所以我们考虑用链表(linked list)
方便起见,常常在链表的第一个元素之前放一个虚拟结点。
每输入一个字符就把它存起来,设输入字符串是s[1~n],则可以用next[i]表示在当前显示屏中s[i]右边的字符编号。
假设字符串s的最前面还有一个虚拟的s[0],则next[0]就可以表示显示屏中最左边的字符,再用一个变量cur表示光标的位置,即当前光标位于s[cur]的右边,cur=0说明光标位于虚拟字符是s[0]的右边,即显示屏的最左边,为了移动光标,还需要用一个变量last表示显示屏的最后一个字符s[last]
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
参考代码:
//破损的键盘.cpp
#include<iostream>
#include<string>
using namespace std;
const int maxn = 100000 + 5;
int last, cur, next[maxn];
char s[maxn];
int main()
{
while(cin >> s+1)
{
int n = strlen(s+1);
last = cur = 0;
next[0] = 0;
for(int i = 1;i <= n;i++)
{
char ch = s[i];
if(ch == '[')cur = 0;
else if(ch == ']')cur = last;
else
{
next[i] = next[cur];
next[cur] = i;
if(cur == last)
last = i;//更新“最后一个字符”编号
cur = i;//移动光标
}
}
for(int i = next[0]; i != 0; i = next[i])
cout << s[i]; //这里将[光标cur放入0的位置
cout << endl;
}
return 0;
}
调试分析:
测试数据:
This_is_a_[Beiju]_text
我们可以分析道显示程序中,next[0] = 12那么i = next[12] = 13所以s从s[13]开始显示。