问题描述
给定一个字符串ss,编写一个函数,将字符串中的小写字母a替换为"%100",并返回替换后的字符串。
例如,对于字符串"abcdwa",所有a字符会被替换为"%100",最终结果为%100bcdw%100"。
题目分析
这个题目比较简单,把字符串中的a字符会被替换为"%100",很直接的想法就是遍历原来的字符串,找到a字符存在的位置,然后利用字符串拼接的方法把a字符进行替换。主要可以总结为如下4个步骤:
- 初始化结果字符串:创建一个新的字符串来存储替换后的结果。
- 遍历输入字符串:逐个字符检查输入字符串,注意这里的输入字符串需要是原来最初的字符串。
- 替换字符:如果当前字符是
'a',则用"%100"替换,我的实现思路是将字符'a'之前的字符和"%100"以及字符'a'之后的字符拼接作为新的字符串, 注意在拼接时,结果字符串的长度会发生变化,因此在下一次出现字符'a'再次进行拼接的时候需要动态调整索引。这里我引入了一个'count'变量来记录进行替换的次数。 - 返回结果字符串:完成遍历后,返回结果字符串。
代码实现
#include <string>
std::string solution(const std::string &s) {
std::string s_new = s;
int count = 0;
for (int i = 0; i < s.size(); ++i) {
if (s[i] == 'a') {
s_new = s_new.substr(0, i + count * 3) + "%100" +
s_new.substr(i + (count * 3) + 1);
count += 1;
}
}
return s_new;
}
int main() {
std::cout << (solution("abcdwa") == "%100bcdw%100") << std::endl;
std::cout << (solution("banana") == "b%100n%100n%100") << std::endl;
std::cout << (solution("apple") == "%100pple") << std::endl;
return 0;
}
代码讲解
if语句判断当前遍历字符是否为'a'。- 如果是
'a',执行替换操作:s_new.substr(0, i + count * 3):提取'a'之前的子字符串。"%100":用"%100"替换'a'。s_new.substr(i + (count * 3) + 1):提取'a'之后的子字符串。
- 替换后的字符串重新赋值给
s_new。 - 注意,
count变量记录替换的次数,因为每次替换后,字符串长度会增加3("%100"替换'a')。
性能与优化
尽管上述代码功能正确,但对于大规模字符串处理可能存在性能瓶颈。
使用流式处理: 替代每次替换后重新创建字符串的做法,可以用一个字符串流逐步拼接结果,这样可以避免频繁的字符串复制操作。
#include <string>
std::string solution(const std::string &s) {
std::string result; // 用于存储替换后的结果字符串
// 遍历输入字符串
for (char c : s) {
if (c == 'a') {
// 如果当前字符是 'a',则追加 "%100" 到结果字符串
result.append("%100");
} else {
// 否则,追加当前字符到结果字符串
result.push_back(c);
}
}
return result; // 返回替换后的结果字符串
}
int main() {
std::cout << (solution("abcdwa") == "%100bcdw%100") << std::endl;
std::cout << (solution("banana") == "b%100n%100n%100") << std::endl;
std::cout << (solution("apple") == "%100pple") << std::endl;
return 0;
}
代码对比
相对于第一段的代码,第二段代码有以下显著的改进和优势:
1. 提高了代码的效率
-
原代码的问题:
- 原代码每次替换
'a'时都会使用substr对字符串进行切割和拼接,这导致了额外的内存分配和字符串复制操作,增加了时间和空间复杂度。 - 每次调用
substr需要创建新的字符串对象,频繁的创建、销毁和拼接字符串对性能非常不利,尤其是当字符串长度较大或替换频率较高时。
- 原代码每次替换
-
改进代码的优势:
- 改进后的代码采用了一个独立的结果字符串
result,通过append和push_back方法直接构建替换后的字符串。append和push_back操作效率更高,因为它们直接在result后追加数据,无需反复创建和销毁临时对象。
- 改进后的代码采用了一个独立的结果字符串
2. 代码简洁,逻辑清晰
-
原代码的复杂性:
- 原代码使用了较为复杂的逻辑来动态调整字符串索引(
count * 3)以处理替换后字符串长度的变化,这使得代码在逻辑上显得臃肿,维护性较差。 - 对于需要频繁替换的场景,这种复杂的索引调整会让代码显得难以阅读和理解。
- 原代码使用了较为复杂的逻辑来动态调整字符串索引(
-
改进代码的简洁性:
- 改进后的代码通过
for (char c : s)直接遍历每个字符,并简单判断是否是'a',逻辑清晰明了,无需考虑替换后字符串长度的动态变化。 - 整体代码更易读、易维护。
- 改进后的代码通过
3. 内存管理更高效
-
原代码的内存问题:
- 原代码每次替换时都会生成新的字符串对象(通过
substr),这导致了频繁的内存分配和释放操作。 - 对于长字符串,内存消耗会显著增加,甚至可能导致内存碎片化。
- 原代码每次替换时都会生成新的字符串对象(通过
-
改进代码的内存优势:
- 改进后的代码只使用一个结果字符串
result,减少了不必要的临时对象创建。 append和push_back在大多数实现中都有优化,能够有效利用内存,无需频繁分配和销毁。
- 改进后的代码只使用一个结果字符串