题目:请实现一个函数,把字符串中的每个空格替换成“%20”。例如输入“We are happy.”,则输出“We%20are%20happy.”。
解题思路
最直观的的做法是从头到尾扫描字符串,每次碰到空格字符的时候进行替换。由于把1个字符换成3个字符,所以必须把空格后面的字符都后移两个单位。例如字符串“We are happy.”,移动过程可由如下示意图表示:
上述解题步骤实现主要代码如下:
#include<iostream> #include<string> #include"stdlib.h" using namespace std; int main() { string str = "We are happy."; int len = str.size(); cout << "原始字符串:" << str << endl; for (int i = 0; i < len; ++i) { if (str[i] == 0x20)//0x20为空格的ANSI码值 { len += 2; str.resize(len);//每查找到一个空格,字符串长度增加2 for (int j = len - 2; j > i; --j) { str[j + 2] = str[j]; } str.replace(i,3,"%20"); } } cout << "替换空格后的字符串:"<< str << endl; system("pause"); return 0; }
假设字符串的长度为n。对每个空格字符,需要移动后面O(n)个字符,因此对于含有O(n)个空格的字符串,时间复杂度为O(n^2),在面试中使用上述的解题步骤,是不能满足面试官要求的。
上述解题步骤时间主要浪费在空格后面字符串的拷贝上。因为每找到一个空格,需要拷贝后面O(n)个字符。所以可从这个角度着手改进。
我们可以从后往前拷贝,这样就可以减少拷贝的次数,每个字符至多移动一次就可以完成。思想是:
1、先扫描一次字符串,统计出空格的个数。然后在尾部分配足够的空间;2、设两个指针oriIndex和newIndex,oriIndex指向原始字符串,newIndex指向重新分配内存后的字符串;
3、从后往前拷贝,如果str[oriIndex]为空格,则在newIndex及其前面两个字符位置处填充”%20”;
4、否则将oriIndex指向的字符复制到newIndex指向的位置。
上述解题步骤实现主要代码如下:
#include<iostream> #include<string> #include"stdlib.h" using namespace std; string ReplaceSpace(string str, int length) { //输入非法检查 if (str.empty() && length <= 0) return str; int oriIndex = length; int newIndex = 0; int num = 0; for (int i = 0; i < length; ++i) { if (str[i] == 0x20)//0x20为空格的ANSI码值 ++num; } length += num * 2;//每查找到一个空格,字符串长度增加2 str.resize(length); newIndex = length; while(oriIndex >= 0 && newIndex > oriIndex) { if (str[oriIndex] == 0x20)//0x20为空格的ANSI码值 { //str[newIndex--] = '0'; //str[newIndex--] = '2'; //str[newIndex--] = '%'; newIndex -= 3; str.replace(newIndex+1, 3, "%20"); } else { str[newIndex--] = str[oriIndex]; } --oriIndex; } return str; } int main() { string str = "We are happy."; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str,len); cout << "替换空格后的字符串:" << str2 << endl; system("pause"); return 0; }
假设字符串的长度为n。每个字符至多移动一次就可以完成,因此对于含有O(n)个空格的字符串,时间复杂度为O(n),优于前一种解题方法。
测试用例1
// 空格在句子中间 void Test1() { string str = "Weare happy."; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }
测试用例2
// 空格在句子开头 void Test2() { string str = " Wearehappy."; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }
测试用例3
// 空格在句子末尾 void Test3() { string str = "Wearehappy. "; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }
测试用例4
// 连续有两个空格 void Test4() { string str = "Weare happy."; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }
测试用例5
// 传入内容为空的字符串 void Test5() { string str = ""; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }
测试用例6
//传入内容为一个空格的字符串 void Test6() { string str = " "; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }
测试用例7
// 传入的字符串没有空格 void Test7() { string str = "Wearehappy."; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }
测试用例8
// 传入的字符串全是空格 void Test8() { string str = " "; int len = str.size(); cout << "原始字符串:" << str << endl; string str2 = ReplaceSpace(str, len); cout << "替换空格后的字符串:" << str2 << endl; }