ACM上一道簡單的字符串題,從網上找了下類似的代碼進行參考外加之個人思考,想到此好思路。
題目大意
任意輸入一行字符串,檢索重復出現的字符。將原字符串中的重復字符刪除后按照原順序輸出,同時按照原順序輸出有哪些字符是重復的。
輸入
輸出
兩個輸出之間空一行
樣例輸入
ads_fagaerididfhdus_afiew
樣例輸出
ads_fgerihuw ads_fei
看到此題,第一想法就是用個初始值全為 0 的flag[100000]數組來進行標記,首先是遍歷整個字符串,從第i個字符開始與整個字符串所有字符(就不單獨把第 i 個字符除開,后面計算時可能有點麻煩,進行判斷時 flag[i] == 1 就行了)進行一一比較,如有重復則flag[i] ++ ,最后通過 flag[i] 的值來判斷。如果 falg[i] == 1 則打印到屏幕上,但是這樣只是把沒有重復的字符打印出來,並沒有將重復的字符刪除而且重復的字符都沒有打印到屏幕上,這樣明顯是不符合題目要求。
那要怎樣呢?是遍歷字符串時把第 i 個字符與字符前或字符后的字符進行對比么,如果這樣可以根據各個重復字符的 flag[i] 進行判斷,到時只需把 flag[i] == 0 和 flag[i] == 2 打印到屏幕上就可以了。這個對題目中的第一要求刪除重復字符按順序打印到屏幕還過得去,不過第二個按照順序提取重復的字符又怎么做?因為重復字符出現可不一定是兩次,這樣 flag[i] 可能為 1、2、3、、4、、、 這樣就不要判斷了。
通過參考網上的代碼,那么這個思路就出來了。眾所周知,我們鍵盤輸入的字符在ASCII字符集都有對應的ASCII碼,把字符的ASCII碼一一對應,可以看成一個容量為 128 的數組,字符ASCII的編碼就在 0-127 之間嘛。此思路也解決前面那種每個位置上的字符都要一個 flag 空間了,只需要 128 容量的空間就足矣。
在這條思路下,我們就初始化所有 flag[128] = {} 在遍歷字符串時先判斷 flag[str[i]] 是否為 0 因為初始都是 0 所以每個字符對應的 ASCII 碼的 flag 都是為 0 的,而在每個進行了判斷且滿足條件的 flag[str[i]] 都改變其值為 1 (不為0即可),這樣當下一個相同字符進行判斷時就不滿足條件被拒之門外,而所有滿足條件的都打印到屏幕上了。這樣子題目的第一要求就滿足了,
那么第二要求呢?還是這個套路,有點像是遞歸的味道。就之前的判斷進行下去,如果進行 str[i] 被拒之門外了怎么辦呢?我們還要打印它一次呢,還有它們了中也是有重復的呀。OK , 舊套路嘛 將上邊不滿足條件的 flag[str[i]] = 2 (不為 1 就行 為了區分就賦值為 3 吧)。
好,這樣之后,所有重復的字符ASCII碼對應的 flag[str[i]] 的值都為 2 了,就像第一要求那樣所有字符對ASCII對應的 flag[str[i]] 都為 0,同樣就可以套用第一要求的代碼模型啦。再來一個for循環,以 flag[str[i]] == 2 作為判斷條件,如果滿足條件則將其改變為 3 (不為 2 就行)。這時不滿足條件的就不管了,因為已達到要求 那些就沒用了,我們將滿足條件的打印到屏幕上就行了。
最后,代碼如下:
#include<stdio.h> #include<string.h> int main(void) { int i; char a[100000]; int flag[128] = {}; gets(a); for(i = 0; i < strlen(a); i ++) if(flag[(int)a[i]] == 0) { flag[(int)a[i]] = 1; printf("%c", a[i]); }//刪除重復字符后按照原順序打印 else flag[(int)a[i]] = 2;
printf("\n\n");//空一行 for(i = 0; i < strlen(a); i ++) if(flag[(int)a[i]] == 2) { flag[(int)a[i]] = 3; printf("%c", a[i]); }//按照原順序打印重復字符 }