剑指offer——2.替换空格

题目描述:

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

解题思路1:

1.本题可使用多种解法,最直观易懂的思路是另外构建一个str,遍历字符串,如果不是空格则复制给str,是空格则str+="20%",直到结尾,然后将str复制给题目要替换的字符串,就可以达到结果,但是时间复杂度较高。

(注:题目未指明参数length到底是字符串实际长度还是最大长度,这里按照实际长度处理)

参考源码1:

class Solution
{
public:
    string res = "";
    void replaceSpace(char *str, int length)
    {
        for (int i = 0; i < length; i++)
        {
            if (str[i] != ' ')
            {
                res += str[i];
            }
            else
            {
                res += "%20";
            }
        }
        for (int i = 0; i < res.length(); i++)
        {
            str[i] = res[i];
        }
    }
};

解题思路2:

直接在所给字符串上进行操作,不构建另外的string,最简单的思路是从前往后遍历,每遇到空格就将后面所有的字符向后移动两位,(因为20%占三位,空格占一位,所以需要向后移动两位),然后将空格替换成20%,但是这种方法时间复杂度高,为O(n^2)。可以先遍历一遍字符串,找到空格数量,然后计算出替换空格之后的总长度,从后往前复制,这样就省去了移动字符所需要花费的时间,时间复杂度为O(n)。

使用两个标志,分别表示两个字符串的当前所在最后一位的位置。

(后两段代码length按照最大长度处理)

参考源码2:


class Solution
{
public:
	void replaceSpace(char *str, int length) //此处的length为str的最大长度
	{
		if (str == NULL || length <= 0) return;
		int len = 0;//原字符串的长度
		int numOfBlank = 0;
		for (int i = 0; str[i] != '\0'; i++)
		{
			len++;
			if (str[i] == ' ')
			{
				numOfBlank++;
			}
		}
		int newlen = len + numOfBlank * 2;//新字符串的长度
		if (newlen > length) return;
		int indexafter = newlen;//这里应当注意,newlen和len都不应减去1,因为字符串结尾还有一个'\0',复制时需要一起复制过去
		int indexbefore = len;
		while (indexbefore >= 0 && indexafter >= indexbefore)
		{
			if (*(str + indexbefore) != ' ')
			{
				*(str + indexafter) = *(str + indexbefore);
			}
			else
			{
				str[indexafter] = '0';
				str[--indexafter] = '2';
				str[--indexafter] = '%';
			}
			indexafter--;
			indexbefore--;
		}
	}
};

解题思路3:

从后往前处理,但不使用两个标志位,将不是空格的每一位直接向后移动count*2位,是空格的位替换成%20.

参考源码3:

class Solution
{
public:
	void replaceSpace(char *str, int length) 
	{
		if (str == NULL || length <= 0) return;
		int len = 0;
		int count = 0;
		while (str[len] != '\0')
		{
			if (str[len] == ' ')
			{
				count++;
			}
            len++;
		}
		if (len > length) return;
		for (int i = len; i >= 0; i--)
		{
			if (str[i] == ' ')
			{
				str[i + count * 2] = '0';
				str[i + count * 2 - 1] = '2';
				str[i + count * 2 - 2] = '%';
				count--;
			}
			else
			{
				str[i + count * 2] = str[i];
			}
		}
	}
};

相关题目:

有两个排序的数组A1和A2,内存在A1的末尾有足够多的空余空间容纳A2。请实现一个函数,把A2中的所有数字插入到A1中并且所有的数字是排序的。

和前面的例题一样,很多人首先想到的办法是在A1中从头到尾复制数字,但这样就会出现多次复制一个数字的情况。更好的办法是从尾到头比较A1和A2中的数字,并把较大的数字复制到A1的合适位置。

举一反三:

合并两个数组(包括字符串)时,如果从前往后复制每个数字(或字符)需要重复移动数字(或字符)多次,那么我们可以考虑从后往前复制,这样就能减少移动的次数,从而提高效率。

猜你喜欢

转载自blog.csdn.net/N1neDing/article/details/81840498