字符串处理是算法面试中的高频考点,也是日常开发中不可或缺的基本功。今天我将分享三个经典的字符串处理问题及其解法,重点剖析双指针技巧在不同场景下的灵活应用。这些题目来自LeetCode和卡码网的实战题库,覆盖了从基础到进阶的字符串操作技巧。
这是最基础的字符串反转问题,要求原地修改输入的字符数组。看似简单,但其中蕴含着重要的算法思想——双指针法。
核心思路:使用两个指针分别指向字符串的首尾,向中间移动并交换元素。这种方法的时间复杂度是O(n),空间复杂度是O(1),是最优解。
cpp复制class Solution {
public:
void reverseString(vector<char>& s) {
for (int i = 0, j = s.size() - 1; i < s.size()/2; i++, j--) {
swap(s[i],s[j]);
}
}
};
注意:循环条件设置为i < s.size()/2即可,因为当指针越过中点时,所有元素已经交换完毕。继续交换会导致字符串恢复原状。
常见错误:
这个问题在基础反转之上增加了规则限制:每计数至2k个字符,就反转前k个字符;如果剩余字符少于k个,则全部反转。
cpp复制class Solution {
public:
string reverseStr(string s, int k) {
int n = s.size();
for (int i = 0; i < n; i += 2 * k) {
int left = i;
int right = min(i + k - 1, n - 1);
while (left < right) {
swap(s[left], s[right]);
left++;
right--;
}
}
return s;
}
};
关键点解析:
实战技巧:处理这类区间问题时,建议先在纸上画出示例字符串和各个指针的位置关系,可以避免很多边界条件错误。
给定一个字符串,将其中的每个数字字符替换为"number"。例如:"a1b2c3"变为"anumberbnumbercnumber"。
这个问题有两种主流解法,各有优劣:
最直观的方法是创建一个新字符串,遍历原字符串并按规则拼接:
cpp复制#include<iostream>
using namespace std;
int main(){
string s;
cin>>s;
string result="";
for(int i=0;i<s.size();i++){
if(s[i]>='0'&&s[i]<='9'){
result+="number";
continue;
}
result.push_back(s[i]);
}
cout<<result;
}
优缺点分析:
更高效的方法是先统计数字个数,扩展字符串大小,然后从后向前替换:
cpp复制#include <iostream>
using namespace std;
int main() {
string s;
while (cin >> s) {
int sOldIndex = s.size() - 1;
int count = 0; // 统计数字的个数
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '0' && s[i] <= '9') {
count++;
}
}
// 扩充字符串s的大小
s.resize(s.size() + count * 5);
int sNewIndex = s.size() - 1;
// 从后往前替换
while (sOldIndex >= 0) {
if (s[sOldIndex] >= '0' && s[sOldIndex] <= '9') {
s[sNewIndex--] = 'r';
s[sNewIndex--] = 'e';
s[sNewIndex--] = 'b';
s[sNewIndex--] = 'm';
s[sNewIndex--] = 'u';
s[sNewIndex--] = 'n';
} else {
s[sNewIndex--] = s[sOldIndex];
}
sOldIndex--;
}
cout << s << endl;
}
}
关键步骤解析:
为什么从后向前处理?因为从前向后处理会导致后面的字符被覆盖。从后向前可以确保被替换的区域已经处理完毕,不会影响未处理的部分。
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 新建字符串法 | O(n) | O(n) | 字符串不大,代码简洁优先 |
| 原地修改法 | O(n) | O(1) | 字符串很大,内存受限 |
在实际面试中,如果能解释清楚两种方法的优劣,并给出适当的选择理由,会大大加分。
通过以上三个问题,我们可以总结出双指针法在字符串处理中的通用模式:
使用双指针法的优势:
常见陷阱:
在多年算法训练和面试准备中,我总结了以下字符串处理的经验:
对于替换数字问题,我最初尝试从前向后替换,结果发现会覆盖后面的字符。这个错误让我深刻理解了为什么这类问题需要从后向前处理。这也是为什么我建议在面试中,即使知道解法,也要先说明你的思考过程,包括可能的问题和解决方案。
在字符串反转的变种问题中,我建议掌握以下几个经典模式:
最后,对于算法训练,我的建议是:理解比记忆更重要。双指针法之所以强大,是因为它符合我们对问题的最直观物理理解——用两个标记点来协同处理数据。掌握这种思维模式,而不仅仅是记住几道题的解法,才能真正提升算法能力。