1. 程式人生 > >Broken Keyboard--又名悲劇文本(線性表)

Broken Keyboard--又名悲劇文本(線性表)

再看 oar 題目 lib 表示 第一個元素 建立 pos 什麽

題目:

你有一個破損的鍵盤。鍵盤上的所有鍵都可以正常工作,但有時Home鍵或者End鍵會自 動按下。你並不知道鍵盤存在這一問題,而是專心地打稿子,甚至連顯示器都沒打開。當你 打開顯示器之後,

展現在你面前的是一段悲劇的文本。你的任務是在打開顯示器之前計算出 這段悲劇文本。 輸入包含多組數據。每組數據占一行,包含不超過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保存“光標位置”。這樣,輸入一個字符相當於在數組中插入一個字符(需要先把後面的字符全部右移,給新字符

騰出位置)。很可惜,這樣的代碼會超時。為什麽?因為每輸入一個字符都可能會引起大量字符移動。在極端情況下,例如,2500000個a和“[”交替出現,則一共需要0+1+2+…+2499999=6*1012次

字符移動。解決方案是采用鏈表(linked list)。每輸入一個字符就把它存起來,設輸入字符串是s[1~n],則可以用next[i]表示在當前顯示屏中s[i]右邊的字符編號(即在s中的下標)。

使用了一個next數組來進行位置索引,用cur和last變量來記錄字符串刪除起始點和終止點。最後輸出由i=Next[0]開始,i==0時作為停止條件,i = Next[i]作為每次循環的刷新。

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(int 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先插到後面next[i]的前面,再把前面i的後面連的那個節點改為新插入的那個j
5.再來說說本題
a.只需改變s的輸出順序,輸出s[next[i]]
b.多了個[],就是說插入的位置會發生變化,怎麽辦?
光標派上用場,
先看一般情況:s[0]0a1b2c3,註意光標的意思,假設光標一開始是0,你輸入a,那1就是此時光標的位置,假設s[1]=a,那我們還沒遍歷到b的時候,next[1]=0(看不懂得話看上面的黑色重點字體),next[0]=1,

這是在s[0]後面插入s[1],(看不懂的話看重新看上面的4),此時如果光標等於最後一個字符的編號(比如last,cur初始值是0,那麽你加了一個字符,最後一個字符編號自然需要更新)就更新最後一個字符編號,

然後把光標改成1 再看特殊的: 如果碰見[,光標跑到0了,把cur改成0 碰見],光標跑到最後一個了數的後面了,你們發現了嗎,最後一個數的下標正好是光標的下標,所以cur=last 。

原理就是下圖表示的樣子??

技術分享圖片

技術分享圖片

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #define maxn 100005
 5 
 6 int cur, last, next[maxn];
 7 char s[maxn];
 8 
 9 int main()
10 {
11     while(scanf("%s",s+1)==1)
12     {
13         int n = strlen(s+1);
14         cur = last = 0;
15         next[0] = 0;
16         for(int i = 1; i <= n; i++)
17         {
18             if(s[i]==[)
19                 cur = 0;         //光標移動到左端
20             else if(s[i]==])
21                 cur = last;       //光標移動到右端
22             else
23             {
24                 next[i] = next[cur];
25                 next[cur] = i;
26                 if(cur == last)
27                     last = i;      //cur == last時文本長度增加
28                 cur = i;              //移動光標
29             }
30         }
31         for(int i = next[0]; i != 0; i = next[i])   將線性表輸出
32             printf("%c",s[i]);
33         printf("\n");
34 
35     }
36     return 0;
37 }

借鑒大佬博客: https://blog.csdn.net/qq_40828914/article/details/81200011

        https://blog.csdn.net/gyh_420/article/details/70175276

        

Broken Keyboard--又名悲劇文本(線性表)