字符串处理是算法面试中的高频考点,而双指针技巧则是解决这类问题的利器。在实际开发中,字符串反转、替换等操作也经常出现在数据处理、文本解析等场景中。
字符串本质上是一个字符数组,在Java中表现为char[]。理解这一点很重要,因为这意味着我们可以使用数组操作来处理字符串问题。例如:
java复制String s = "hello";
char[] chars = s.toCharArray(); // 转为字符数组
这种转换让我们能够利用数组的随机访问特性(O(1)时间复杂度访问任意元素),这在处理字符串问题时非常有用。
双指针法通过维护两个指针(通常是索引)来协同工作,常见的有以下几种模式:
提示:在处理字符串/数组问题时,先思考是否可以用双指针法,这通常能带来O(n)时间复杂度的解决方案。
这是最基本的反转问题,要求原地修改输入数组。双指针解法如下:
java复制public void reverseString(char[] s) {
int left = 0, right = s.length - 1;
while (left < right) {
// 交换左右指针指向的字符
char temp = s[left];
s[left] = s[right];
s[right] = temp;
// 移动指针
left++;
right--;
}
}
时间复杂度分析:O(n),其中n是字符串长度。我们只需遍历一半的数组。
空间复杂度:O(1),只使用了常数级别的额外空间。
这个问题增加了间隔反转的条件,需要更精细的指针控制:
java复制public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for (int i = 0; i < ch.length; i += 2 * k) {
int start = i;
// 确定反转的结束位置
int end = Math.min(ch.length - 1, start + k - 1);
// 执行反转
while (start < end) {
char temp = ch[start];
ch[start] = ch[end];
ch[end] = temp;
start++;
end--;
}
}
return new String(ch);
}
关键点:
注意:边界条件的处理是这类问题的难点,务必仔细检查指针的移动和终止条件。
将数字替换为"number"的特殊之处在于:
为什么选择从后向前处理?
java复制import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int len = s.length();
// 第一步:计算新长度
for (int i = 0; i < s.length(); i++) {
if (Character.isDigit(s.charAt(i))) {
len += 5; // "number"比数字多5个字符
}
}
// 第二步:创建足够大的数组
char[] ret = new char[len];
// 第三步:初始化数组(复制原字符串)
for (int i = 0; i < s.length(); i++) {
ret[i] = s.charAt(i);
}
// 第四步:从后向前替换
int i = s.length() - 1, j = len - 1;
while (i >= 0) {
if (Character.isDigit(ret[i])) {
// 反向填充"number"
ret[j--] = 'r';
ret[j--] = 'e';
ret[j--] = 'b';
ret[j--] = 'm';
ret[j--] = 'u';
ret[j--] = 'n';
} else {
ret[j--] = ret[i];
}
i--;
}
System.out.println(new String(ret));
}
}
优化技巧:
Character.isDigit()方法判断数字更可靠在字符串问题中,常见的边界情况包括:
调试方法:
对于大规模字符串处理:
在实际面试中,字符串问题常常作为考察候选人编码能力和边界条件处理能力的题目。掌握双指针技巧不仅能解决这类问题,还能培养出更高效的算法思维。建议在理解这些基础问题后,尝试解决更复杂的字符串处理问题,如实现基本的正则表达式匹配或字符串压缩算法。