一、題目描述
請實現一個函數,將一個字符串中的空格替換成“%20”。例如,當字符串為We Are Happy.則經過替換之后的字符串為We%20Are%20Happy。
二、解題思路
1)簡單暴力解法,我們可以很容易的想到,碰到一個空格,就加入%20,於是可以從頭到尾遍歷字符串,碰到空格,首先將后面的所有字符串往后移動2個字符,這樣才能空出3個字符位子插入字符“%20”,對於一個長度為n的字符串,對每個空格,需要移動后面O(n)個字符,因此包含n個空格的字符串,總的時間復雜度為O(n*n)。這個代碼就不寫了...
2)我們仔細的思考,難道我們真的只能0(n*n)的復雜度嗎?不,我們可以更快!
我們從后往前開始替換,首先遍歷一遍字符串,統計出空格的個數,並由此能夠計算出替換之后的字符串的長度。
舉個例子:
每替換一個空格,長度增加2,因此替換以后字符串的長度等於原來的長度加上2乘以空格數目。以"We are happy"為例,"We are happy"這個字符串的長度為14(包括結尾符號"\n"),里面有兩個空格,因此替換之后字符串的長度是18。
接着再次從后往前遍歷字符串,同時設置兩個指針P1和P2,P1指向原始字符串末尾,P2指向替換之后的字符串末尾。我們向前移動P1,逐個把它指向的字符復制到P2指向的位置,直到碰到第一個空格為止。然后把P1向前移動一格,在P2之前插入字符串“%20”,同時P2向前移動3格。重復此過程,直到所有的空格都已替換完。這樣只需要掃描一遍,時間復雜度為O(n)。
移動示意圖如下:

#include <iostream>
#include <iterator>
using namespace std;
void replaceSpace(char* str,int length) {
char* ots = NULL;
if (str == NULL && length <= 0) {
return;
}
/*original_length為字符串str的實際長度*/
int original_length = 0; //原始長度
int number_blank = 0; //空格數
int i = 0;
while (str[i++] != '\0') { //遍歷字符串
++original_length; //長度+1
if (str[i] == ' ') {
++number_blank; //遇到空格+1
}
}
/*new_length為把空格替換成'%20'之后的長度*/
int new_length = original_length + 2 * number_blank;
ots = (char*)malloc(new_length * sizeof(char));
memset(ots, 0, strlen(ots));
if (ots == NULL) return;
memcpy(ots, str, strlen(str));
int index_original = original_length; //原始字符串末尾索引值
int index_new = new_length; //計算長度后的字符串末尾索引值
/*index_original指針開始向前移動,如果遇到空格,替換成'%20',否則進行復制操作*/
while (index_original >= 0 && index_new > index_original) {
if (ots[index_original] == ' ') {
ots[index_new--] = '0';
ots[index_new--] = '2';
ots[index_new--] = '%';
}
else {
ots[index_new--] = ots[index_original];
}
--index_original;
}
cout << ots << endl;
};
int main()
{
const char* tmp = "wu han tai re li";
char* p = const_cast<char*>(tmp);
replaceSpace(p, strlen(p));
return 0;
}
事實上,很多網絡上的代碼你是絕對編譯不通過的,原因很簡單,str被重新計算了,然后用新的大小去索引,不崩潰才怪。
