1. 字符串算法实战:从回文检测到高精度运算
在算法面试和实际工程中,字符串处理是永恒的主题。今天我想分享三个经典的字符串算法问题及其优化解法,这些技术不仅出现在大厂面试中,也广泛应用于文本处理、编译器设计和金融计算等领域。
2. 最长回文子串:中心扩展法的艺术
2.1 问题定义与核心思路
给定一个字符串s,找到其中最长的回文子串。回文串是指正读反读都相同的字符串,如"aba"、"abba"。
中心扩展法的核心思想是:每个回文串都有一个中心(奇数长度)或两个中心(偶数长度)。我们遍历字符串,以每个字符为中心向两边扩展,寻找可能的回文串。
关键点:需要考虑奇数和偶数长度两种情况,分别处理才能覆盖所有可能性
2.2 实现细节与优化
java复制class Solution {
public String longestPalindrome(String s) {
int begin = 0, maxLen = 0;
for (int i = 0; i < s.length(); i++) {
// 奇数情况
int len1 = expandAroundCenter(s, i, i);
// 偶数情况
int len2 = expandAroundCenter(s, i, i + 1);
int currentMax = Math.max(len1, len2);
if (currentMax > maxLen) {
begin = i - (currentMax - 1) / 2;
maxLen = currentMax;
}
}
return s.substring(begin, begin + maxLen);
}
private int expandAroundCenter(String s, int left, int right) {
while (left >= 0 && right < s.length()
&& s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}
}
2.3 时间复杂度分析
- 时间复杂度:O(n²),n为字符串长度。每个字符作为中心最多扩展n次
- 空间复杂度:O(1),只使用了常数个额外变量
实际工程中,当处理超长文本时,可以考虑Manacher算法(O(n)时间复杂度),但实现复杂度较高。
3. 二进制求和:高精度运算基础
3.1 问题背景与应用场景
给定两个二进制字符串,返回它们的和(仍以二进制表示)。这个问题看似简单,但当数字超过基本数据类型范围时,就需要高精度运算技术。
这类技术在以下场景至关重要:
- 区块链中的哈希计算
- 金融系统的精确计算
- 密码学中的大数运算
3.2 算法实现与位运算技巧
java复制class Solution {
public String addBinary(String a, String b) {
StringBuilder sb = new StringBuilder();
int i = a.length() - 1, j = b.length() - 1;
int carry = 0;
while (i >= 0 || j >= 0 || carry != 0) {
int sum = carry;
if (i >= 0) sum += a.charAt(i--) - '0';
if (j >= 0) sum += b.charAt(j--) - '0';
sb.append(sum % 2);
carry = sum / 2;
}
return sb.reverse().toString();
}
}
3.3 关键点解析
- 从右向左逐位相加,模拟手工计算过程
- 使用carry变量记录进位
- 处理不同长度字符串的情况
- 最后需要反转结果字符串
实际开发中,这种技术可以扩展到任意进制(如16进制)的加法运算
4. 字符串相乘:高精度乘法的两种实现
4.1 方法一:传统竖式乘法
4.1.1 算法步骤
- 从右到左遍历乘数的每一位
- 将被乘数与当前位相乘,得到部分积
- 根据位数补零(相当于左移)
- 将所有部分积相加
java复制class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) return "0";
String result = "0";
for (int i = num2.length() - 1; i >= 0; i--) {
StringBuilder temp = new StringBuilder();
// 补零
for (int j = 0; j < num2.length() - 1 - i; j++) {
temp.append(0);
}
int digit = num2.charAt(i) - '0';
int carry = 0;
for (int j = num1.length() - 1; j >= 0; j--) {
int product = (num1.charAt(j) - '0') * digit + carry;
temp.append(product % 10);
carry = product / 10;
}
if (carry != 0) temp.append(carry);
result = addStrings(result, temp.reverse().toString());
}
return result;
}
private String addStrings(String num1, String num2) {
// 同前面的加法实现
}
}
4.1.2 复杂度分析
- 时间复杂度:O(mn + n²),其中m和n是两个数的位数
- 空间复杂度:O(m+n)存储中间结果
4.2 方法二:优化版无进位乘法
4.2.1 算法创新点
- 先不考虑进位,计算每位乘积
- 将乘积结果存入对应位置
- 最后统一处理进位
java复制class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) return "0";
int m = num1.length(), n = num2.length();
int[] pos = new int[m + n];
for (int i = m - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
int p1 = i + j, p2 = i + j + 1;
int sum = mul + pos[p2];
pos[p1] += sum / 10;
pos[p2] = sum % 10;
}
}
StringBuilder sb = new StringBuilder();
for (int p : pos) {
if (!(sb.length() == 0 && p == 0)) {
sb.append(p);
}
}
return sb.length() == 0 ? "0" : sb.toString();
}
}
4.2.2 性能对比
- 时间复杂度:O(mn)
- 空间复杂度:O(m+n)
- 优势:减少了中间字符串操作,性能更好
5. 工程实践中的注意事项
5.1 边界条件处理
- 输入为空字符串的情况
- 全零输入的特殊处理
- 前导零的去除
- 大数运算时的内存管理
5.2 性能优化技巧
- 使用StringBuilder代替String拼接
- 预先分配足够容量避免扩容
- 尽量减少不必要的对象创建
- 考虑使用位运算替代部分算术运算
5.3 测试用例设计
有效的测试用例应包括:
- 常规情况(普通输入)
- 边界情况(空串、单字符、全零)
- 大数测试(超过long范围的数字)
- 性能测试(超长字符串)
6. 算法扩展与应用
6.1 其他高精度运算
- 高精度减法
- 高精度除法
- 高精度模运算
- 高精度幂运算
6.2 实际应用场景
- 密码学中的大素数运算
- 区块链中的哈希计算
- 科学计算中的精确浮点运算
- 金融系统中的精确金额计算
在实现这些算法时,我最大的体会是:理解比记忆更重要。掌握核心思想后,可以根据具体场景灵活调整实现方式。比如在内存受限的环境下,可能需要更注重空间效率;而在高频交易系统中,时间效率可能更为关键。