『嗨威說』數據結構 - 第四章學習內容小結
一道天梯賽搞得全場人崩潰的題,幾乎現場就沒幾個人AC,現在回頭看看,真的很考細節耐心地題目。
-----------------------------題目-----------------------------
- 無論用戶說什麽,首先把對方說的話在一行中原樣打印出來;
- 消除原文中多余空格:把相鄰單詞間的多個空格換成 1 個空格,把行首尾的空格全部刪掉,把標點符號前面的空格刪掉;
- 把原文中所有大寫英文字母變成小寫,除了 I;
- 把原文中所有獨立的 I 和 me 換成 you;
- 把原文中所有的問號 ? 換成驚嘆號 !;
- 把原文中所有獨立的 can you 換成 I can —— 這裏“獨立”是指被空格或標點符號分隔開的單詞;
- 在一行中輸出替換後的句子作為 AI 的回答
輸入樣例:
6 Hello ? Good to chat with you can you speak Chinese? Really? Could you show me 5 What Is this prime? I,don ‘t know
輸出樣例:
Hello ? AI: hello! Good to chat with you AI: good to chat with you can you speak Chinese? AI: I can speak chinese! Really? AI: really! Could you show me 5 AI: could you show you 5 What Is this prime? I,don ‘t know AI: what Is this prime! you,don‘t know
-----------------------------題目-----------------------------
一、正式題解:
1* 函數原型聲明:
void deleteSymbolSpace(); void deleteSpace(); void bigToSmall();void changePersonY(); void changePersonI(); void changeQ(); bool isIndenpend(char temp);
deleteSymbolSpace —— 刪除符號前的空格
deleteSpace —— 刪除多余空格
bigToSmall —— 將大寫轉小寫
changePersonY —— 改變人稱You
changePersonI —— 改變人稱I me
changeQ —— 問號改為感嘆號
isIndenpend —— 判斷是否獨立函數
2* 主函數框架構建:
int main() { scanf("%d",×); getchar(); while(times--) { memset(temp,0,sizeof(temp)); memset(tMark,0,sizeof(tMark)); cin.getline(temp,1000); puts(temp); changeQ(); bigToSmall(); deleteSpace(); changePersonY(); changePersonI(); deleteSpace(); deleteSymbolSpace(); printf("AI: "); puts(temp); } return 0; }
拋開細節的實現方式,從大局角度思考程序的運行方式。
3*deleteSymbolSpace的實現:
void deleteSymbolSpace() { memset(dealing,0,sizeof(dealing)); count = 0; for(int i = 0;i<strlen(temp);i++) { if(temp[i] == 32) { int flag = 0; if(temp[i+1]>=33 && temp[i+1]<=47) flag = 1; else if(temp[i+1]>=58 && temp[i+1]<=64) flag = 1; else if(temp[i+1]>=91 && temp[i+1]<=96) flag = 1; else if(temp[i+1]>=123 && temp[i+1]<=126) flag = 1; if(flag == 1) { dealing[count] = temp[i+1]; count++; i=i+1; } else { dealing[count] = temp[i]; count++; } } else { dealing[count] = temp[i]; count++; } } dealing[count] = ‘\0‘; memset(temp,0,sizeof(temp)); strcpy(temp,dealing); }
因為剛開始不知道判斷字母和數字的函數,所以幹脆直接簡單粗暴,ASCII掃獨立。
4* deleteSpace函數的實現:
void deleteSpace() { int start = 0; int space = 0; memset(dealing,0,sizeof(dealing)); count = 0; for(int i = 0;i<strlen(temp);i++) { if(start == 0 && temp[i] == 32) continue; else if(start == 0 && temp[i] != 32) { start = 1; dealing[count] = temp[i]; count++; continue; } if(temp[i] == 32) { if(space == 1) continue; if(tMark[i] == 1) continue; space = 1; dealing[count] = 32; count++; } else { space = 0; dealing[count] = temp[i]; count++; } } if(dealing[count-1] == 32) dealing[count-1] = ‘\0‘; else dealing[count] = ‘\0‘; memset(temp,0,sizeof(temp)); strcpy(temp,dealing); }
核心思路很簡單,就是拿一個新數組去存新的結果,通過打標記判斷是否是句頭空行。
5* bigToSmall函數的實現:
void bigToSmall()//實際上可以用tolower代替 { for(int i = 0;i<strlen(temp);i++) { if( temp[i] >= 65 && temp[i] <= 90) { if(temp[i] == ‘I‘) continue; temp[i] = temp[i] + 32; } } }
這裏也是因為不知道有tolower這個魔鬼函數,所以依舊簡單粗暴,暴力用ASCII解決問題。
6* changePersonY函數的實現:
void changePersonY() { for(int i = 0;i<strlen(temp);i++) { int flag = -1; if(i != 0 && !isIndenpend(temp[i-1])) continue; if(temp[i] == ‘c‘ && temp[i+1] == ‘a‘ && temp[i+2] == ‘n‘) flag = 3; else if(temp[i] == ‘c‘ && temp[i+1] == ‘o‘ && temp[i+2] == ‘u‘ && temp[i+3] == ‘l‘ && temp[i+4] == ‘d‘) flag = 5; if(flag != -1) { int mark = 0; if(temp[i+flag]>=32 && temp[i+flag]<=47) mark = 1; else if(temp[i+flag]>=58 && temp[i+flag]<=64) mark = 1; else if(temp[i+flag]>=91 && temp[i+flag]<=96) mark = 1; else if(temp[i+flag]>=123 && temp[i+flag]<=126) mark = 1; if(mark == 1) { if(temp[i+flag+mark] == ‘y‘ && temp[i+flag+mark+1] == ‘o‘ && temp[i+flag+mark+2] == ‘u‘) { if(temp[i+flag+mark+3] != ‘\0‘ && !isIndenpend(temp[i+flag+mark+3])) continue; temp[i] = ‘I‘; tMark[i] = 1; temp[i+1] = temp[i+flag]; if(flag == 3) { temp[i+2] = ‘c‘; temp[i+3] = ‘a‘; temp[i+4] = ‘n‘; } else if(flag == 5) { temp[i+2] = ‘c‘; temp[i+3] = ‘o‘; temp[i+4] = ‘u‘; temp[i+5] = ‘l‘; temp[i+6] = ‘d‘; } temp[i +flag+2] = ‘ ‘; temp[i +flag+3] = ‘ ‘; tMark[i +flag+2] = tMark[i +flag+3] = 1; i = i +flag+3; } } } } }
轉換人稱是所有限制條件最麻煩最難的地方,需要註意打上標記,因為對string還是有點小反感,雖然挺好用,但是習慣用char進行單個強行處理,所以這裏一直是用char來處理的~
7* changePersonI函數的實現:
void changePersonI() { memset(dealing,0,sizeof(dealing)); count = 0; for(int i = 0;i<strlen(temp);i++) { if(temp[i] == ‘I‘ && isIndenpend(temp[i+1]) && tMark[i] == 0) { if(i != 0 && !isIndenpend(temp[i-1])) { dealing[count] = temp[i]; count++; continue; } dealing[count] = ‘y‘; dealing[count+1] = ‘o‘; dealing[count+2] = ‘u‘; count += 3; } else if(temp[i] == ‘m‘ && temp[i+1] == ‘e‘ && isIndenpend(temp[i+2])) { if(i != 0 && !isIndenpend(temp[i-1])) { dealing[count] = temp[i]; count++; continue; } dealing[count] = ‘y‘; dealing[count+1] = ‘o‘; dealing[count+2] = ‘u‘; count += 3; i = i + 1; } else { dealing[count] = temp[i]; count++; } } dealing[count] = ‘\0‘; memset(temp,0,sizeof(temp)); strcpy(temp,dealing); }
這裏尤其需要註意,不能把已經換過的人稱再換一次,所以需要對標記進行判斷。
8* changeQ的函數實現:
void changeQ() { for(int i = 0;i<strlen(temp);i++) if(temp[i] == ‘?‘) temp[i] = ‘!‘; }
盡管函數簡單,但盡量單獨列出,使程序更加結構化。
9* isIndenpend函數的實現:
bool isIndenpend(char temp) { int mark = 0; if(temp>=32 && temp<=64) mark = 1; else if(temp>=91 && temp<=96) mark = 1; else if(temp>=123 && temp<=126) mark = 1; else if(temp == ‘\0‘) mark = 1; return mark; }
暴力ASCII碼解決,雖然不是最佳的處理方式。
二、完整代碼展示:
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; //------------------------ void deleteSymbolSpace(); void deleteSpace(); void bigToSmall(); void changePersonY(); void changePersonI(); void changeQ(); bool isIndenpend(char temp); //------------------------ int times; char dealing[1001]; int count; char temp[1001]; int tMark[1001]; int main() { scanf("%d",×); getchar(); while(times--) { memset(temp,0,sizeof(temp)); memset(tMark,0,sizeof(tMark)); cin.getline(temp,1000); puts(temp); changeQ(); bigToSmall(); deleteSpace(); changePersonY(); changePersonI(); deleteSpace(); deleteSymbolSpace(); printf("AI: "); puts(temp); } return 0; } void deleteSymbolSpace() { memset(dealing,0,sizeof(dealing)); count = 0; for(int i = 0;i<strlen(temp);i++) { if(temp[i] == 32) { int flag = 0; if(temp[i+1]>=33 && temp[i+1]<=47) flag = 1; else if(temp[i+1]>=58 && temp[i+1]<=64) flag = 1; else if(temp[i+1]>=91 && temp[i+1]<=96) flag = 1; else if(temp[i+1]>=123 && temp[i+1]<=126) flag = 1; if(flag == 1) { dealing[count] = temp[i+1]; count++; i=i+1; } else { dealing[count] = temp[i]; count++; } } else { dealing[count] = temp[i]; count++; } } dealing[count] = ‘\0‘; memset(temp,0,sizeof(temp)); strcpy(temp,dealing); } void deleteSpace() { int start = 0; int space = 0; memset(dealing,0,sizeof(dealing)); count = 0; for(int i = 0;i<strlen(temp);i++) { if(start == 0 && temp[i] == 32) continue; else if(start == 0 && temp[i] != 32) { start = 1; dealing[count] = temp[i]; count++; continue; } if(temp[i] == 32) { if(space == 1) continue; if(tMark[i] == 1) continue; space = 1; dealing[count] = 32; count++; } else { space = 0; dealing[count] = temp[i]; count++; } } if(dealing[count-1] == 32) dealing[count-1] = ‘\0‘; else dealing[count] = ‘\0‘; memset(temp,0,sizeof(temp)); strcpy(temp,dealing); } void bigToSmall()//實際上可以用tolower代替 { for(int i = 0;i<strlen(temp);i++) { if( temp[i] >= 65 && temp[i] <= 90) { if(temp[i] == ‘I‘) continue; temp[i] = temp[i] + 32; } } } void changePersonY() { for(int i = 0;i<strlen(temp);i++) { int flag = -1; if(i != 0 && !isIndenpend(temp[i-1])) continue; if(temp[i] == ‘c‘ && temp[i+1] == ‘a‘ && temp[i+2] == ‘n‘) flag = 3; else if(temp[i] == ‘c‘ && temp[i+1] == ‘o‘ && temp[i+2] == ‘u‘ && temp[i+3] == ‘l‘ && temp[i+4] == ‘d‘) flag = 5; if(flag != -1) { int mark = 0; if(temp[i+flag]>=32 && temp[i+flag]<=47) mark = 1; else if(temp[i+flag]>=58 && temp[i+flag]<=64) mark = 1; else if(temp[i+flag]>=91 && temp[i+flag]<=96) mark = 1; else if(temp[i+flag]>=123 && temp[i+flag]<=126) mark = 1; if(mark == 1) { if(temp[i+flag+mark] == ‘y‘ && temp[i+flag+mark+1] == ‘o‘ && temp[i+flag+mark+2] == ‘u‘) { if(temp[i+flag+mark+3] != ‘\0‘ && !isIndenpend(temp[i+flag+mark+3])) continue; temp[i] = ‘I‘; tMark[i] = 1; temp[i+1] = temp[i+flag]; if(flag == 3) { temp[i+2] = ‘c‘; temp[i+3] = ‘a‘; temp[i+4] = ‘n‘; } else if(flag == 5) { temp[i+2] = ‘c‘; temp[i+3] = ‘o‘; temp[i+4] = ‘u‘; temp[i+5] = ‘l‘; temp[i+6] = ‘d‘; } temp[i +flag+2] = ‘ ‘; temp[i +flag+3] = ‘ ‘; tMark[i +flag+2] = tMark[i +flag+3] = 1; i = i +flag+3; } } } } } void changePersonI() { memset(dealing,0,sizeof(dealing)); count = 0; for(int i = 0;i<strlen(temp);i++) { if(temp[i] == ‘I‘ && isIndenpend(temp[i+1]) && tMark[i] == 0) { if(i != 0 && !isIndenpend(temp[i-1])) { dealing[count] = temp[i]; count++; continue; } dealing[count] = ‘y‘; dealing[count+1] = ‘o‘; dealing[count+2] = ‘u‘; count += 3; } else if(temp[i] == ‘m‘ && temp[i+1] == ‘e‘ && isIndenpend(temp[i+2])) { if(i != 0 && !isIndenpend(temp[i-1])) { dealing[count] = temp[i]; count++; continue; } dealing[count] = ‘y‘; dealing[count+1] = ‘o‘; dealing[count+2] = ‘u‘; count += 3; i = i + 1; } else { dealing[count] = temp[i]; count++; } } dealing[count] = ‘\0‘; memset(temp,0,sizeof(temp)); strcpy(temp,dealing); } void changeQ() { for(int i = 0;i<strlen(temp);i++) if(temp[i] == ‘?‘) temp[i] = ‘!‘; } bool isIndenpend(char temp) { int mark = 0; if(temp>=32 && temp<=64) mark = 1; else if(temp>=91 && temp<=96) mark = 1; else if(temp>=123 && temp<=126) mark = 1; else if(temp == ‘\0‘) mark = 1; return mark; }
三、個人反思:
AI這道題還有待進一步優化和升級,還有一個bug沒有發現,還會繼續解決,重點想講的是程序設計的架構:
框架化的程序設計方法,是很早在Quanta冬令營中安卓JAVA的設計學習而得,由此類比過來的。我覺得,倘若要成為合格的程序設計師,出外工作的話,對框架的把握是非常重要的一個關卡,代碼是否結構化明顯,是否符合公司開發要求,是否易讀都是程序設計過程中非常關鍵的地方。在安卓中,有分層WEB層、底層、數據層、素材動畫層等等,選用合理的框架,能對團隊的程序設計帶來極大的效益,因此這個思想需要堅持並保留下來。
接下來的學習歷程吧:
=》學習十字鏈表以及線性樹、主席樹、區間更新等ACM問題,為5月12日的廣東省ACM省賽做準備
=》學習統計學習方法,掌握模型評估、決策樹、向量機等知識,為數據挖掘實驗室——多模態情感分析項目組努力。
=》前陣子七周都在英劇上花了不少時間,學習有些耽誤,後續時間將慢慢追回學業,保證學業狀態。
哦對了,順便附加ACM中的KMP模板吧,挺好用的,直接背下來用就好了~
int KMP(char* str,char* pat) { int i,j,k; memset(fail,-1,sizeof(fail)); for(i = 1;pat[i];++i) { for(k = fail[i-1];k>=0 && pat[i] != pat[k+1];k = fail[k]); if(pat[k+1] == pat[i]) fail[i] = k + 1; } i = j = 0; while(str[i] && pat[j]) { if(pat[j] == str[i]) ++i,++j; else if(j == 0) ++i; else j = fail[j-1] + 1; } if(pat[j]) return 0; else return i-j+1; }View Code
『嗨威說』數據結構 - 第四章學習內容小結