【剑指offer 5题】替换空格

本文介绍了一种高效的字符串空格替换算法,通过双指针从后向前扫描,避免了传统方法中字符多次移动的问题,实现了O(n)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述

二、思路

要求:在原来的字符串上进行替换

思路一 

常规的思路就是计算遍历一边数组,碰到空格就替换,为了防止字符被覆盖,再替换的时候,空格后面的字符串要统一向后移动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;
}

运行结果:

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值