网上的正确代码很多,我在这里只是想记录一下自己解题中的所有问题,希望能通过总结与反思使自己能稍稍有所提高。
题目:将一个字符串中的每个空格替换成“%20”.例如:we are happy.-----> we%20are%20happy.
阶段一:基础知识回顾
因为真的好久没有编代码了,所以想自己动手把涉及到的基础知识补回来,而不是看一眼别人的代码知道这里就是这个样子。
1、字符串长度:
类模板传入的参数有长度,在定义不同字符串和字符数组的时候,具体的长度以及函数用法会有所不同,可参考
博客:https://blog.csdn.net/z_qifa/article/details/77744482(sizeof()、strlen()、length()、size()详解和区别)
2、用指针的时候,内存地址变化,以及返回的内存地址。
这里是因为开始在Vs上可以编译通过,但是牛客网上不通过,查看论坛的时候看到有人这样说了一下,
然后就进行了单步调试以及内存检测,发现str地址真的发生了变化
阶段二:摸清题目真实意图
根据何海涛《剑指offer》
1、内存覆盖:若直接把空格替换成 %20,那字符串总长度会变长,会覆盖在该字符串后面的内存。
2、时间复杂度:
①从前往后替换的话,在遇到第一个空格时,后面的部分需要整体往后挪动两格,给 ‘2’‘0’ 腾出来位置,在遇到第二个空格的时候,这后面的整体同样需要再往后挪动两格。
由此可知,对于长度为n的字符串,如果有n个空格,那么时间复杂度就是O(n*n).
②从后往前替换。 先正序遍历字符串,统计出空格的数量,得到替换后字符串的总长度;然后定义两个指针p1,p2,
分别指向原字符串末尾、替换后字符串末尾;开始从后向前遍历,如果遇到空格,p2-- = 0;p2-- = 2;p2-- = %;
即p2指针向前移动三格,同时插入‘%20’,如果没有遇到空格,把p1的值赋值给p2--即可;p1在每次遍历的时候向前移动一格;当p1和p2指向同一个位置的时候,证明所有空格替换完毕。
上述方法,所有的字符只用复制一次(移动),时间效率是O(n).
阶段三:实现算法调试Bug阶段
1、判断相等 语句
if (str[i] == ' ') 出错: 写成 = ,这是好低级的错误,会出现中断错误,切记不可再错!
2、str[i] 和 *str 都是可以的
根据前面分析 ,需要建立两个指向末尾的指针,有两种方法:
2.1、指针指向字符串末尾
char *pStr1 = str + Originallength; // 字符指针指向原始字符串的末尾
char *pStr2 = str + len; // 字符指针指向替换后字符串的末尾
while (pStr1 != pStr2) // 替换结束的条件
{
if (*pStr1 == ' ')
{
*pStr2-- = '0';
*pStr2-- = '2';
*pStr2-- = '%';
}
else
{
*pStr2-- = *pStr1;
}
--pStr1;
}
2.2、用字符数组,不过索引改成新的长度
int indexOfOriginal = Originallength;
int indexOfNew = newLength;
while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
{
if (str[indexOfOriginal] == ' ')
{
str[indexOfNew--] = '0';
str[indexOfNew--] = '2';
str[indexOfNew--] = '%';
}
else
{
str[indexOfNew--] = str[indexOfOriginal];
}
--indexOfOriginal;
}
3、可以看子程序中返回的str地址:
printf("%p\n",&str[0]);
传入的字符串首地址:0117FBDC //原字符串所分配内存地址
新建字符串-地址:0117FAD4 //新建一个字符串,进行赋值替换操作,返回地址不对
指针型——地址:0117FBDC // 返回地址和原内存分配的地址一致
字符数组——地址:0117FBDC
所有正确代码:
class Solution2 //先查出来一共有多少空格,然后从后往前替换
{
public:
void replaceSpace(char *str, int length)
{
//边界检查1:判断字符串是否为空
if (str == NULL||length<=0)
return;
//遍历字符串,统计空格数、替换前字符个数、替换后字符个数
int CountOfBlanks = 0; //空格个数
int Originallength = 0; //替换前字符个数
int newLength = 0; //替换后字符个数
for (int i = 0; str[i] != '\0'; ++i)
{
Originallength++;
if (str[i] == ' ')
++CountOfBlanks;
}
newLength = Originallength + 2 * CountOfBlanks;
//边界检查2:判断字符数组是否越界
if (newLength + 1 > length)
return;
//替换空格
int indexOfOriginal = Originallength;
int indexOfNew = newLength;
while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
{
if (str[indexOfOriginal] == ' ')
{
str[indexOfNew--] = '0';
str[indexOfNew--] = '2';
str[indexOfNew--] = '%';
}
else
{
str[indexOfNew--] = str[indexOfOriginal];
}
--indexOfOriginal;
}
cout << str << endl;
printf("字符数组——地址:%p\n\n", &str[0]);
}
};
class Solution3 {
public:
// 指向字符数组的字符指针str,字符数组长度length
void replaceSpace(char *str, int length) {
// 边界检查1:判断字符数组是否为空
if (str == NULL)
return;
// 遍历字符串,统计空格个数、替换前字符个数、替换后字符个数
int CountOfBlanks = 0; // 空格个数
int Originallength = 0;// 替换前字符个数
int len = 0; // 替换后字符个数
for (int i = 0; str[i] != '\0'; ++i)
{
Originallength++;
if (str[i] == ' ')
++CountOfBlanks;
}
len = Originallength + 2 * CountOfBlanks;
// 边界检查2:判断字符数组是否越界
if (len + 1>length)
return;
// 替换空格
char *pStr1 = str + Originallength;// 字符指针指向原始字符串的末尾
char *pStr2 = str + len; // 字符指针指向替换后字符串的末尾
while (pStr1 != pStr2) // 替换结束的条件
{
if (*pStr1 == ' ')
{
*pStr2-- = '0';
*pStr2-- = '2';
*pStr2-- = '%';
}
else
{
*pStr2-- = *pStr1;
}
--pStr1;
}
cout << str << endl;
printf("指针型——地址:%p\n\n", &str[0]);
}
};
int main()
{
Solution2 B2;
Solution3 B3;
const int length = 100;
char str[length] = "We are happy.";
printf("传入的字符串首地址:%p\n\n",&str[0]);//地址用十六进制表示
B2.replaceSpace(str, length);
B3.replaceSpace(str, length);
system("pause");
}