首先明确C++中每个字符串都以‘\0’作为结尾,例如字符串“12345”实际长度是6个字节,如果要复制该字符串,至少需要6个字节的数组。
面试题:
int main()
{
char str1[]="hello world";
char str2[]="hello world";
char*str3="hello world";
char*str4="hello world";
if(str1==str2)
printf("str1 and str2 are same.\n");
else printf("str1 and str2 are not same.\n");
if(str3==str4)
printf("str3 and str4 are same.\n");
else printf("str4 and str4 are not same.\n");
return 0;
}
输出:
解析:str1和str2是两个字符串数组,会被分配两个长度是12字节的空间,两个数组的初始地址不同,因此str1和str2也不同
str3和str4是两个指针,不需要为他们分配内存存储字符串的内容,只需要使他们指向“hello world”字符串的首地址即可。
“hello world”是一个字符串常量,其在内存中只有一个拷贝,因此str3和str4指向同一个地址。所以str3和str4是相同的。
题目描述
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路:
题目要求是:原来的一个空格被替换成‘%’、‘2’、‘0’这三个字符
有两种解法:
1、可以创建新的字符串,并在新的字符串上替换字符,这个很简单,新创建一个字符串数组,移动并替换字符即可。
时间复杂度:O(n)
空间复杂度:O(n)
2、在原来的字符数组上替换,则需要移动每个空格之后的字符
思路:为了使时间复杂度更低,我们必须减少字符移动的次数,最好遍历一次数组就全部移动完毕最好。
1、先遍历一遍字符串,统计空格的总数N,则原字符串长度需要增加2*N
2、开始从后往前遍历,用p1指向原来字符串长度的尾部,p2指向后来字符串长度的尾部
3、逐个将p1指向的字符复制到p2指向的空格中(图a)
4、当遇到空格时,p2向前移动3个空格,依次存储‘0’、‘2’、‘%’,p1向前移动一格
时间复杂度:O(n)
空间复杂度:O(1)
代码:
/*length 为字符串数组的总容量*/
class Solution {
public:
string replaceSpace(string s) {
if(s.size()==0) {
return "";
}
int cnt = 0;
for(int i = 0; i < s.size(); i++)
{
if(s[i] == ' ') {
cnt++;
}
}
int p = s.size()-1; //防止访问越界
int q = p+cnt*2;
//首先分配新空间
s += string(cnt * 2,' ');
while(p>=0 && p<=q)
{
if(s[p]==' ') {
s[q--]='0';
s[q--]='2';
s[q--]='%';
p--;
} else {
s[q--]=s[p--];
}
}
return s;
}
};
举一反三:
当合并两个数组(或者字符串)牵涉到元素移动问题时,如果从前往后移动需要复制并移动每个元素多次,那么可以考虑从后往前移动,以减少复制和移动的次数,提高效率。
相关题目:
有两个排序数组A1和A2,内存在A1的末尾有足够多的空余空间容纳A2。请实现一个函数,把A2中的所有数字插入A1中,并且所有的数字是排序的。
更好的思想是从尾到头比较A1和A2中的数字,并把较大的数字复制到A1中的合适位置