剑指offer (05):替换字符串中空格 (C++ & Python 实现)

1 题目:

请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We are happy.”,则输出“We%20are%20happy.”

2 题解

2.1 暴力解法 O(n2)

依次扫描字符串,遇到空格,则将后面字符向后移动两个单位,并从当前位置开始添加字符%20

假设字符串长度为 n,对每个空格字符,需要移动后面 O(n) 个字符,因此对于含有 O(n) 个空格字符的字符串而言,总的时间效率是 O(n2)。

2.2 优雅解法 O(n)

我们换一种思路,把从前向后替换 改成 从后向前替换

首先遍历一次字符串,统计字符串中空格的总数,以此计算替换之后的新字符串的长度。每替换一个空格,长度加 2,因此新字符串的长度等于原始长度加上 2 乘以空格总数。

首先准备两个指针,P1 指向原始字符串的末尾,P2 指向新字符串的末尾。接着向前移动 P1 ,逐个把它指向的字符复制到 P2 指向的位置,直到碰到第一个空格为止。

碰到空格后,P1 向前移动一格,P2 向前移动 3 格并插入%20 。直到P1 P2指向同一位置,替换完毕。

上面这种方法,只移动了一次,所以时间复杂度是O(n)。

3 代码

C++

#include <iostream>

using namespace std;

class Solution
{
public:
	// length 为字符数组 string 的总容量
	void ReplaceBlank(char str[], int length)
	{
		if (str == nullptr && length <= 0)
			return;
		/*originalLength 为字符串str的实际长度*/
		int originalLength = 0;
		
		int numberOfBlank = 0; // 空格数目
		int i = 0;
		
		while (str[i] != '\0') // 计算实际长度,空格数
		{
			++originalLength;
			
			if (str[i] == ' ')
				++numberOfBlank;
			++i;
		}
		cout << originalLength << endl;
		/*newLength 为把空格替换成“%20”之后的长度*/
		int newLength = originalLength + numberOfBlank * 2;
		if (newLength > length)
			return;
		int indexOfOriginal = originalLength; // 指向实际长度末尾
		int indexOfNew = newLength; // 指向新长度的末尾
		while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
		{
			if (str[indexOfOriginal] == ' ') // 若指针1扫描到空格,则依次向前添加字符
			{
				str[indexOfNew--] = '0';
				str[indexOfNew--] = '2';
				str[indexOfNew--] = '%';
			}
			else // 若指针1没有扫描到空格
			{
				// 则移动位置
				str[indexOfNew--] = str[indexOfOriginal];
			}
			--indexOfOriginal;
		}
	}

	// 暴力,O(n2)
	void replaceBlankForce(char str[], int length)
	{
		if (str == nullptr && length <= 0)
			return;

		int originalLength = 0;

		int i = 0;
		while (str[i] != '\0') // 计算实际长度
		{
			++originalLength;
			++i;
		}
		i = 0;
		int newLength = originalLength;
		while (str[i] != '\0')
		{
			if (str[i] == ' ') // 若碰到一次空格,则后面就要移动一次位置
			{
				newLength += 2;
				for (int j = newLength; j > i; j--)
				{
					str[j] = str[j-2];
				}
				str[i++] = '%';
				str[i++] = '2';
				str[i++] = '0';
			}
			else i++;
		}
	}
};

int main()
{
	const int length = 100;
	char str[length] = "hello world";

	Solution solu;
	solu.ReplaceBlank(str, length);

	cout << str << endl;
	cin.get();
	return 0;
}

Python

class Solution:
    
    # 使用append依次遍历即可替换 O(n)
    def replaceSpaceByAppend(self, s):
        string = list(s)
        stringReplace = []
        for item in string:
            if item == ' ':
                stringReplace.append('%')
                stringReplace.append('2')
                stringReplace.append('0')
            else:
                stringReplace.append(item)
        return "".join(stringReplace)

    # 字符串拼接
    def replaceSpaceByStr(self, s):
        temp = ''
        if type(s) != str: return "Wrong! You should input a str!"
        for c in s:
            if c == ' ':
                temp += '%20'
            else:
                temp += c
        return temp

    def replaceSpaceByBultin(self, s):
        if type(s) != str:
            return
        return s.replace(' ', '%20')

    # 书中方法,python实现起来麻烦且慢,不推荐
    def replaceSpace(self, s):
        if not isinstance(s,str) or len(s) <= 0 or s == None:
            return ""
        spaceNum = 0
        for i in s:
            if i == " ":
                spaceNum += 1

        newStrLen = len(s) + spaceNum * 2
        newStr = newStrLen * [None]
        indexOfOriginal, indexOfNew = len(s) - 1, newStrLen - 1
        while indexOfNew >= 0 and indexOfNew >= indexOfOriginal:
            if s[indexOfOriginal] == ' ':
                newStr[indexOfNew-2:indexOfNew+1] = ['%', '2', '0']
                indexOfNew -= 3
                indexOfOriginal -= 1
            else:
                newStr[indexOfNew] = s[indexOfOriginal]
                indexOfNew -= 1
                indexOfOriginal -= 1
        return "".join(newStr)

s = 'Hello World!'
a = 123
solu = Solution()
print(solu.replaceBlank(s))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值