Broken Keyboard (a.k.a. Beiju Text)

原题及翻译

Broken Keyboard (a.k.a. Beiju Text)
破碎的键盘(a.k.a. Beiju Text)
You’re typing a long text with a broken keyboard.
您正在键入一个破碎键盘的长文本。
Well it’s not so badly broken.
好吧,它没有那么糟糕。
The only problem with the keyboard is that sometimes the “home” key or the “end” key gets automatically pressed (internally).
键盘的唯一问题是有时“自动”键或“结束”键被自动按下(内部)。
You’re not aware of this issue, since you’re focusing on the text and did not even turn on the monitor!
你不知道这个问题,因为你专注于文本,甚至没有打开监控!
After you finished typing, you can see a text on the screen (if you turn on the monitor).
键入完成后,您可以在屏幕上看到文本(如果打开显示器)。
In Chinese, we can call it Beiju.
在中文里,我们可以称之为悲剧。
Your task is to find the Beiju text.
你的任务是找到悲剧文本。

Input

There are several test cases.
有几个测试用例。
Each test case is a single line containing at least one and at most 100,000 letters, underscores and two special characters ‘[’ and ‘]’.
每个测试用例都是一行,包含至少一个,最多100,000个字符,下划线和两个特殊字符’[‘和’]’。
‘[’ means the “Home” key is pressed internally, and ‘]’ means the “End” key is pressed internally.
'[‘表示内部按下“Home”键,’]表示内部按下“End”键。
The input is terminated by end-of-file(EOF).
输入由文件结束(EOF)终止。

Output

For each case, print the Beiju text on the screen.
对于每种情况,请在屏幕上打印悲剧文本。

Sample Input

This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University

Sample Output

BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University

分析

最简单的想法便是使用数组来保存这段文本,然后用一个变量post保存“光标位置”。这样,输入一个字符相当于在数组中插入一个字符(需要先把后面的字符全部右移,给新字符腾出位置)。

但是,这样的代码会超时,因为输入一个字符都可能会引起大量字符移动。

解决方案是采用链表(linked list)。每输入一个字符就把它存起来,设输入字符串是s[1~n],则可以用next[i]表示在当前显示屏中s[i]右边的字符编号(即在s中的下标)。

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

为了方便起见,假设字符串s的最前面还有一个虚拟的s[0],则next[0]就可以表示显示屏最左边的字符。再用一个变量char表示光标位置:即当前光标位于s[cur]的右边。cur=0说明光标位于“虚拟字符”s[0]的右边,即显示屏的最左边。

为了方便起见,常常在链表的第一个元素之前放一个虚拟结点。

为了移动光标,还需要一个变量last表示显示屏的最后一个字符是s[last]。

代码

#include <cstdio>
#include <cstring>
const int maxn=100000+5;
int last,cur,next[maxn];    //光标位于cur号字符的后面
char s[maxn];

int main()
{
	while(scanf("%s",s+1)==1)
	{
		int n=strlen(s+1);    //输入保存在s[1],s[2]…中
		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])
			printf("%c",s[i]);
		printf("\n");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/AlexKing007/p/12339201.html