1. 程式人生 > >UVA11988(破損鍵盤) 使用陣列模擬連結串列插入

UVA11988(破損鍵盤) 使用陣列模擬連結串列插入

  開始刷資料結構相關的題了,在筆試和麵試過程中如果要寫出指標形式的連結串列時間上可能不夠。該題很好地訓練了怎麼使用陣列來模擬連結串列
  破損的鍵盤(又名:悲劇文字)(Broken Keyboard(a.k.a. Beiju Text),
UVa 11988)
你有一個破損的鍵盤。鍵盤上的所有鍵都可以正常工作,但有時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]作為每次迴圈的重新整理。

這裡提供兩幅圖來理解這個演算法,next數組裡面存的值是指向了下一次next陣列索引的序號以及這次我們在字串陣列s中索引到的值。第一幅是無’[’ ‘]’的情況

這裡寫圖片描述

// UVA11988(破損鍵盤).cpp : 定義控制檯應用程式的入口點。
//

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

char s[101000];
int Next[101000];

int main()
{
    int cur, last;//cur為游標位置,last為顯示屏最後一個字元
while (~scanf("%s", s + 1)) { memset(Next, 0, sizeof(Next)); int len = strlen(s + 1); Next[0] = 0; cur = last = 0; for (int i = 1; i <= len; i++) { if (s[i] == '[') cur = 0; else if (s[i] == ']') cur = last; else { //模擬插入連結串列過程 Next[i] = Next[cur];//第i個字元指向游標位置 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"); memset(s, 0, sizeof(s)); } return 0; }