例,請實現一個函式,把字串中的每個空格替換成“%20”。例如輸入“We are happy.”,則輸出“We%20are%20happy.”。
分析:
我們可以先遍歷一次字串,這樣就能統計出字串中空格的總數,並可以由此計算出替換之後的字串的總長度。每替換一個空格,長度增加2,因此替換以後字串的長度等於原來的長度加上2乘以空格數目。我們還是以前面的字串’We are happy,”為例,”We are happy‘”這個字串的長度是14(包括結尾符號”),裡面有兩個空格,因此替換之後字串的長度是18。
我們從字串的後面開始複製和替換。首先準備兩個指標,P1和P2。P1指向原始字串的末尾,而P2指向替換之後的字串的末尾(如圖(a)所示)。接下來我們向前移動指標P1,逐個把它指向的字元複製到P2指向的位置,直到碰到第一個空格為止。此時字串包含如圖(b)所示,灰色背景的區域是做了字元拷貝(移動)的區域。碰到第一個空格之後,把Pl向前移動1格,在P2之前插入字串”%20″。由於”%20″的長度為3,同時也要把P2向前移動3格如圖(c)所示。
我們接著向前複製,直到到碰到第二個空格(如圖2.4(d)所示)。和上次一樣,我們再把P1向前移動1格,並把P2向前移動3格插入”%20″(如圖2.4(e)所示)。此時P1和P2指向同一位置,表明所有空格都已經替換完畢。 從上面的分析我們可以看出,所有的字元都只複製(移動)一次,因此這個演算法的時間效率是O(n),效率比較高。
注:圖中帶有陰影的區域表示被移動的字元。
(a)把第一個指標指向原字串的末尾,把第二個指標指向替換之後的字串的末尾。
(b)依次複製字串的內容,直至第一個指標碰到第一個空格。
(c)把倒數第一個空格替換成”%20″,接著,把第一個指標向前移動1格,把第二個指標向前移動3格。
(d)依次向前複製字串中的字元,直至碰到空格。
(e)替換字串中的倒數第二個空格,接著,把第一個指標向前移動1格,把第二個指標向前移動3格。
在面試的過程中,我們也可以和前面的分析一樣,畫一兩個示意圖,解釋自己的思路,這樣既能幫助我們理清思路,也能使我們和麵試官的交流變得更加高效。在面試官肯定我們的思路之後,就可以開始寫程式碼了。下面是參考程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//length為字元陣列string的總容量 void ReplaceBlank(char str[],int length) { if(str==NULL && length<=0) return; //originalLength為字串str的實際長度 int originalLength=0; int numberOfBlank=0; int i=0; while (str[i]!='\0') { ++originalLength; if(str[i]==' ') ++numberOfBlank; ++i; } //newLength為把空格替換成'%20'之後的長度 int newLength=originalLength + numberOfBlank*2; if(newLength>length) return; int indexOfOriginal=originalLength; int indexOfNew=newLength; while (indexOfOriginal>=0 && indexOfNew>indexOfOriginal) { if (str[indexOfOriginal]==' ') { str[indexOfNew--]='0'; str[indexOfNew--]='2'; str[indexOfNew--]='%'; } else { str[indexOfNew--]=str[indexOfOriginal]; } --indexOfOriginal; } } |
測試用例:
1)輸入的字串中包含空格(空格位於字串的最前面,空格位於字串的最後面,空格位於字串的中間,字串中有連續多個空格)。
2)輸入的字串中沒有空格。
3)特殊輸入測試(字串是個NULL指標、字串是個空字串、字串只有一個空格字元、字串中只有連續多個空格)。
//測試程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
void Test(char* testName, char string[], int length, char expected[]) { if(testName != NULL) printf("%s begins: ", testName); ReplaceBlank(string, length); if(expected == NULL && string == NULL) printf("passed.\n"); else if(expected == NULL && string != NULL) printf("failed.\n"); else if(strcmp(string, expected) == 0) printf("passed.\n"); else printf("failed.\n"); } // 空格在句子中間 void Test1() { const int length = 100; char string[length] = "hello world"; Test("Test1", string, length, "hello%20world"); } // 空格在句子開頭 void Test2() { const int length = 100; char string[length] = " helloworld"; Test("Test2", string, length, "%20helloworld"); } // 空格在句子末尾 void Test3() { const int length = 100; char string[length] = "helloworld "; Test("Test3", string, length, "helloworld%20"); } // 連續有兩個空格 void Test4() { const int length = 100; char string[length] = "hello world"; Test("Test4", string, length, "hello%20%20world"); } // 傳入NULL void Test5() { Test("Test5", NULL, 0, NULL); } // 傳入內容為空的字串 void Test6() { const int length = 100; char string[length] = ""; Test("Test6", string, length, ""); } //傳入內容為一個空格的字串 void Test7() { const int length = 100; char string[length] = " "; Test("Test7", string, length, "%20"); } // 傳入的字串沒有空格 void Test8() { const int length = 100; char string[length] = "helloworld"; Test("Test8", string, length, "helloworld"); } // 傳入的字串全是空格 void Test9() { const int length = 100; char string[length] = " "; Test("Test9", string, length, "%20%20%20"); } |
//主函式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int _tmain(int argc, _TCHAR* argv[]) { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); Test7(); Test8(); Test9(); return 0; } |
效果如下:
參考文獻:何海濤.《劍指Offer名企面試官精講典型程式設計題》.2012年.電子工業出版社