你还在为找不到心仪的offer发愁吗?还在为面试担心吗?和我一起,提起剑来,攻克面试的种种难关!直指心仪offer!!!
![](https://i-blog.csdnimg.cn/blog_migrate/a0ee5d98680278e2a3d42301a0061687.jpeg#pic_center)
题目二:请实现一个函数,将一个字符串中的空格替换成%20。例如“We are happy.”,替换成“We%20are%20happy.”
分析:首先,我们应该想到原来的一个空格字符,替换成了’%’,‘2’,‘0’,三个字符,替换后字符串长度会变长,如果在原字符串上修改,会覆盖后面的字符。所以需要考虑后面的字符串移动问题。或者,我们新开辟一块内存空间,在新内存块区域赋值。因此有两种做法,第二种做法空间复杂度较高,而且过于简单,我们不做讨论。只讨论在原来字符串基础上怎么替换。
方法一:时间复杂度为O(n^2),不足以搞定Offer
最直观的就是从头到尾依次扫描字符串,每次碰到空格时,将后面的字符串向后移动两个字节,再将空出来的三个字节赋值为%20。对长度为n的字符串,由于每次遇到字符串时,都要移动O(n)个字符,对含O(n)个空格的字符串而言,总时间复杂度为O(n^2)。因此此方法不是很完美。
方法一:时间复杂度为O(n),搞定Offer就靠它了
上述方法时间复杂度太大,关键就是对靠后一点的字符,移动的次数太多。遇到一个空格,移动O(n)次,再遇到一个空格,再移动O(n)次。如果空格特别多,这个过程就特别麻烦了。
那我们发现,对后面的某个字符来说,前面每遇到一个空格,就要向后移动两个字节。那如果说,我事先知道,这个字符串中共有m个空格,那我总共需要移动2m个字节,这样一来,对后面的某个字符来说,只需要移动一次。如果有n个字符,那总共只需要移动n次。因此,此方法时间复杂度为O(n),比上面那个方法就要好的多了。
那这个方法具体该怎么实现呢。我们设原字符串s的长度为 len 。然后先遍历一遍字符串,求出它里面的空格数,进一步求出修改后的字符串的长度 s_len 后。我们可以构造两个指针 p、q 。指针p 指向原字符串的末尾 s[len] , 指针q 指向我们即将改好的字符串末尾 s[s_len] 。然后依次将指针 p 和指针 q 往前扫描,如果不是空格,直接将指针 p 指向的空间向指针 q 指向的空间赋值。如果遇到空格,指针 p 先不动,移动指针 q 从后往前依次赋值 ‘0’、 ‘2’、 ‘%’ 。直到遍历到字符串起始位置。
具体代码如下:
#include<iostream>
using namespace std;
void Replace_Spaces(char*s, int Cap)
{
if (nullptr==s)
{
cout << "字符串不合法!" << endl;
return;
}
int i = 0,len = 0, count = 0;
while (s[i] != '\0')
{
++len;
if (' ' == s[i])
++count;
i++;
}
int s_len = len + 2 * count;
if (s_len > Cap)
{
cout << "空间不足,替换失败!" << endl;
return;
}
int p = len;
int q = s_len;
while (p >= 0&&p<q)
{
if (' ' == s[p])
{
s[q--] = '0';
s[q--] = '2';
s[q] = '%';
}
else
{
s[q] = s[p];
}
--p;
--q;
}
}
int main()
{
char* s;
int n=0;
cout << "请输入空间大小:>" << endl;
while (cin >> n, n <= 0)
{
cout << "空间不合法,请重新输入";
}
s = (char*)malloc(sizeof(char)*n);
cout << "请输入一个字符串:>" << endl;
getchar();
gets(s);
Replace_Spaces(s, n);
cout << "替换后的字符串为:" ;
puts(s);
return 0;
}
运行结果如下:
**文章系本人原创,转载请注明作者和出处。**