《剑指offer》上的一道题,P44,把字符串中的每个空格换成“%20”,例如 输入 Hello[][]World! 输出Hello%20%20World!
1.原来的字符串空间足够大,在原来字符串上做替换;
2.创建新的字符串并在新的字符串上做替换。
针对1,用“倒着”复制的方法,先统计出原字符串中空格的个数numb,再将原来的字符串空间扩充为s.size()+numb*2. 用两个指针,一个指针P1指向原来字符串的末尾,另一个指针P2指向替换后字符串的末尾。向前移动P1,如果遇到空格,则P1向前移动1,在P2前插入“%20”,P2向前移动3;如果遇到的不是不空格,P1向前移动,逐个把P1所指的元素复制到P2上,P2同时向前移动1.
一开始写的代码如下:
1 string replaceBlank(string s){ 2 int numb = 0; 3 for (int i = 0; s[i]; i++){ 4 if (s[i] == ' ') numb++; // numb存储空格的个数 5 } 6 int newLength = s.size() + numb*2; // 要填充的是三个字符,所以空间扩大numb*2 7 for (int i = newLength - 1, j = s.size() - 1; j >= 0; --j){ 8 9 if (s[j] == ' '){ 10 s[i--] = '0'; 11 s[i--] = '2'; 12 s[i--] = '%'; 13 } 14 else s[i--] = s[j]; 15 16 } 17 return s; 18 }
但是最后测试结果有错,输入hello[][]world,输出为hello%20%20w 把后面的orld截掉了。以为的是string会自动扩充内存空间,因此可以直接有s[i],其中i>s.size()。搜索了下关于string类的扩充内存空间,想起了容器的resize()函数,就把string::resize()给加进去,结果才对……其实对于为什么是这样还不清楚。是因为使用了string的下标形式,类似于一个字符串数组,而数组的空间是固定的吗?
【更新】string的下标形式:标准库不要求检查索引值,所用索引的下标越界是没有定义的,这样往往会导致严重的运行时错误。所以之前是下标越界的情况吧。
关于string::resize() http://www.cplusplus.com/reference/string/string/resize/
修改后如下:
1 string replaceSpace(string s){ 2 int numb = 0; 3 for (int i = 0; i < s.size(); i++){ 4 if (s[i] == ' ') numb++; 5 } 6 int oriLength = s.size(); 7 int newLength = oriLength + numb*2; 8 s.resize(newLength); // 必须resize 9 for (int i = newLength - 1, j = oriLength - 1; j >= 0; --j){ 10 11 if (s[j] == ' '){ 12 s[i--] = '0'; 13 s[i--] = '2'; 14 s[i--] = '%'; 15 } 16 else s[i--] = s[j]; 17 18 } 19 return s; 20 }
再后来,搜索的过程中看了别人的用新创建一个字符串的形式来做替换思路也很简单。这里新创建的string初始化为空,不使用下标……使用stl的append()进行末尾插入。
1 string replaceBlank(string s){ 2 string temp = ""; 3 for (int i = 0; i < s.size(); i++){ 4 if (s[i] == ' '){ 5 temp.append("%20"); 6 } 7 else 8 temp.push_back(s[i]); 9 } 10 return temp; 11 }