替换空格
题目描述
请实现一个函数,把字符串中的每个空格替换成"%20"。例如,输入 “We are happy.”,输出“We%20are%20happy.”
分析
显然,最直观的解法就是从头到尾遍历输入字符串,遇到空格则进行替换,但是由于替换后的"%20"是3个字符,而原本的空格只有1个字符,替换过程中必然会出现需要将空格后的字符向后移动的情况。例如输入“We are happy.”进行第一个空格替换时,"are happy."需要向后移动两个位置,而进行第二个空格的替换时,"happy."又需要移动一次,也就是说每个空格的替换都会导致其后面的字符发生一次移动。对于长度为n的字符串,包含O(n)个空格,每个空格的替换导致其后面O(n)个字符的移动,其时间复杂度为O(n^2)。
为了降低时间复杂度,我们可以考虑从后向前进行替换。首先遍历一遍输入字符串记录空格的数量,这样就可以计算得到替换后字符串的长度。然后用两个索引idOld, idNew分别指示原始字符串与输入字符串的元素下标,初始化为字符串各自的最后一个下标。接着从后向前,若原始字符串idOld位置不是空格,则赋值给新字符串对应idNew位置;否则,则从后向前向新字符串赋值’0’, ‘2’, ‘%’。这一过程要注意每次对新字符串赋值后索引idNew都要递减1,遍历原始字符串idOld位置的元素后也要对idOld递减1.
C++代码如下。目前采用的是vector来记录输入输出,实际采用char str[]或string类型是一样的,注意边界即可。算法上主要注意要考虑到正向遍历的额外开销,实现上则要注意索引值的递减。
vector<char> replaceBlank(vector<char> str) {
int len = str.size(), numBlank = 0;
for (auto c : str) {
if (c == ' ') ++numBlank;
}
int newLen = len + 2 * numBlank;
vector<char> ans(len);
int idOld = len - 1, idNew = newLen - 1;
while (idOld >= 0 && idNew >= 0) {
if (str[idOld] == ' ') {
ans[idNew--] = '0';
ans[idNew--] = '2';
ans[idNew--] = '%';
} else {
ans[idNew--] = str[idOld];
}
--idOld;
}
return ans;
}