题目
请实现一个函数,把字符串中的每个空格替换成“%20”。例如,输入“We are happy.",
则输出"We%20are%20happy."。
首先拿到题目,第一感觉就是一个 ‘空格’ 变成了 ‘%20’ 那字符串长度肯定变长啊
所以我第一反应是创建新的字符串B,然后从A一个个读取字符,遇到‘空格’就用 ‘%20’ 来替代,只要B空间足够,遍历一遍就成了。
但是,面试再简单也不是考这种题目。
于是这时候面试官可能会讲了:
要求在原来的字符串上进行操作
这时候问题就有点意思了,长度变长绝对会覆盖后面的字符,那么肯定需要移动后面的字符,移就移呗,总比不动好,于是:
- 时间复杂度O(n2)的解决办法(想拿offter没门)
思路很简单,当我遇到一个空格时,就将后面的字符全部后移2位,填充%20后,继续遍历,遇到空格就后移,直到最后。
可以看到,“are” 被移动了1次,”happy"移动了2次。要是空格多了,而且又分布在前面岂不是凉凉。
所以要另找出路,就想降低移动次数,正着不行,反着总可以了吧
既然长度要变,不是可以把长度给算出来么,一个萝卜一个坑,一一对应总不会错。
- 时间复杂度O(n)的解决办法(面试官会心一笑)
不过我们可以从尾巴开始
1、先遍历一遍字符串,将空格个数计数出来,算出最终字符串总长度
2、利用两个指针P1、P2。一开始P1指向原始字符串末尾,P2只想最终的末尾。
3、P1一格一格向前移动,每移动一次,就将指向的字符(非空)复制到P2(复制完后P2也随之向前移动一格)
4、当P1遇到空格时,P2所在的地方依次填充 0 2 % (即倒着的%20)
5、如果P1与P2相遇了,那么就停止,否则继续进行
来个图示比较清楚
我们发现所有的字符值移动了1次,这样时间效率提高了,复杂度就变为了O(n)
好了,思路有了,直接敲代码
void ReplaceBlank(char string[],int length)
{
if(string==nullptr || length<=0) return;
//记录原始长度 以及 空格数量
int originalLength=0;
int numberOfBlank=0;
int i=0;
while(string[i]!='\0')
{
++originalLength;
if(string[i]=='') ++numberOfBlank;
++i;
}
//新的长度
int newLength = originalLength+numberOfBlank*2;
if(newLength>length) return;
//"指针" P1 P2
int indexOfOriginal=originalLength;
int indexOfNew=newLength;
while(indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
{
if(string[indexOfOriginal]==' ') //填充
{
string[indexOfNew--]='0';
string[indexOfNew--]='2';
string[indexOfNew--]='%';
}
else
string[indexOfNew--]=string[indexOfOriginal];
--indexOfOriginal;
}
}
————————————————————————————————————————————————————
参考书籍:《剑指offer 第二版》