攻克名企面试题,剑指心仪offer!——题目2 字符串 替换空格


        你还在为找不到心仪的offer发愁吗?还在为面试担心吗?和我一起,提起剑来,攻克面试的种种难关!直指心仪offer!!!




题目二:请实现一个函数,将一个字符串中的空格替换成%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;
}

运行结果如下:
在这里插入图片描述


**文章系本人原创,转载请注明作者和出处。**

猜你喜欢

转载自blog.csdn.net/xiaomu_Y/article/details/106478849