题目:请实现一个函数,把字符串中的每个空格替换成”%20”。例如输入“We are happy.”,则输出“We%20are%20happy.”。
常规思路:从头到尾扫描字符串,每一次碰到空格,必须先把空格后面的所有字符都后移两个字节(否则就有两个字符被覆盖了),然后再替换空格。此种方法,对于长度为n的字符串来说,算法的时间复杂度为O(n2)
为了减少移动次数,换一种思路:从前向后替换改为从后向前替换,时间复杂度变为O(n)
实现步骤:
(1)先遍历一次字符串,统计出字符串中空格的总数,并由此计算出替换之后的字符串的总长度=原来的长度+空格数*2
(2)从字符串后面开始复制和替换。准备两个指针P1和P2,P1指向原始字符串的末尾,P2指向指向替换之后的字符串的末尾。 向前移动指针P1,逐个把它指向的字符复制到P2指向的位置,直到碰到第一个空格为止。(3)碰到第一个空格,把P1向前移动一格,P2移动三格(因为插入的字符串%20长度是3),在P2之前插入字符串“%20”。接着向前复制,直到碰到第二个空格,同理。
(4)当P1和P2指向同一位置,表明所有空格都已经替换完毕。可以分析出,所有的字符只复制(移动)一次,因此这种方法的时间复杂度是O(n)
代码如下:
void ReplaceBlank(char string[], int length) //length为字符数组string的总容量,大于或等于字符串string的实际长度
{
if(string == nullptr || length <=0)
return; //用于返回类型为void的函数,return语句是为了引起函数的强制结束,这种用法类似于循环结构中的break语句的作用。
int originalLength = 0; //定义变量originalLength为字符串string的实际长度,初始值为0
int numberofBlank = 0; //定义变量numberofBlank为字符串string的空格数,初始值为0
int i = 0;
while(string[i] != '\0') //遍历字符串,统计出字符串中空格的总数,并存于变量numberofBlank
{
++ originalLength;
if(string[i] == ' ')
++ numberofBlank;
++ i;
}
int newLength = originalLength + numberofBlank * 2; //newLength 为把空格替换成'%20'之后的字符串长度
if(newLength > length) //若新的字符串长度大于字符数组string的总容量则无法插入
return;
int p1 = originalLength; //此处就像前面分析的,定义了变量p1和p2,虽然不是指针,但用在string数组中就相当于指针p1和p2,
int p2 = newLength; //string[p1]初始值指向原始字符串的末尾,string[p2]初始值指向替换的字符串的末尾
while(p1 >= 0 && p2 > p1) //放字符
{
if(string[p1] == ' ') //判断string[p1]是否指向空格,若是将p2依次向前移动,进行替换
{
string[p2 --] == '0';
string[p2 --] == '2';
string[p2 --] == '%';
}
else //若string[p1]指向的不是空格,则把string[p1]指向的字符复制到string[p2]中,并将p2向前移动一位
{
string[p2 --] = string[p1];
}
-- p1; //每次操作完,将p1向前移动一位
}
}