一、问题描述
二、思路
要求:在原来的字符串上进行替换
思路一
常规的思路就是计算遍历一边数组,碰到空格就替换,为了防止字符被覆盖,再替换的时候,空格后面的字符串要统一向后移动2格。
如图(b),遇到第一个空格的时候are happy.\0统一向后移动两格;如图(c),遇到第二个空格的时候happy.\0统一向后移动两格,这时happy.\0移动了两次,效率不高。
假设字符串长度为n,遇到每个空格,空格后的字符要移动O(n)次,如果有n个空格,那么空格后的字符要移动O(n*n)次,时间复杂度高。
思路二:
首先,先遍历一遍字符串,计算出字符串的空格数n,再根据空格数可以算出替换后的字符串长度为(len+2*n);
其次,我们使用指针p1指向原子符串的末尾,用指针p2指向替换后的字符串的末尾,从后向前扫描;
p1一边往前走,一边将字符拷贝给p2,(p1--,p2--),当p1遇到空格的时候,将p1向前移动一格,在p2前依次插入0、2、%(即p2会移动三格)
之后同理,p1一直先前移动,并将值拷给p2,直到遇到空格,插入0、2、%
此时,p1、p2指向同一位置,即所有空格替换完成。
我们可以看出,这种方法使得每个字符只用移动一次,因此这个算法的时间复杂度为O(n),效率更高。
三、代码实现
#include<iostream>
using namespace std;
//数组中空格的数目
int GetBlank(char *arr,int length)
{
if(arr == NULL || length <= 0)//不要忘写
{
return 0;
}
int i = 0;
int len = 0;
int count = 0;//用来记录数组中的空格数
for(i;arr[i] != '\0';i++)
{
if(arr[i] == ' ')
{
++count;
}
}
return count;
}
void newWord(char *arr,int length)
{
int n = GetBlank(arr,length);
int i = 0;
int len1 = 0;
for(i;arr[i] != '\0';++i)//计算数组中字符串长度
{
len1++;
}
int len2 = len1+2*n;//替换后的字符串长度
if(len2 > length)//判断替换后的字符数组是否越界(不要忘写)
{
return;
}
//让p1指向原字符串的末尾,p2指向新字符串的末尾
char *p1 = &arr[len1];//arr+len1;
char *p2 = arr+len2;
while(p1 != p2)//直到两个指针指向同一位置,替换完成
{
if(*p1 != ' ')//如果p1指向的内容不是空格的话,将p1的内容拷贝给p2,并且p1、p2都向前走一格
{
*p2-- = *p1;
}
else//如果p1指向的内容不是空格的话,p2移动并p2依次赋值0、2、%
{
*p2-- = '0';
*p2-- = '2';
*p2-- = '%';
}
--p1;
}
}
int main()
{
char arr[100] = {"A B C H"};
cout<<GetBlank(arr,100)<<endl;
newWord(arr,100);
cout<<arr<<endl;
return 0;
}
运行结果: