字符串反轉是面試高頻題,也是理解 Java 數據結構、算法思想的絕佳切入點。本文實現 5 種經典算法,分析時空複雜度、適用場景與性能特徵。
public String reverseByArray(String str) {
if (str == null || str.length() <= 1) return str;
char[] ch = str.toCharArray();
for (int i = 0, j = ch.length - 1; i < j; i++, j--) {
char temp = ch[i];
ch[i] = ch[j];
ch[j] = temp;
}
return new String(ch);
}
public String reverseByStack(String str) {
if (str == null || str.length() <= 1) return str;
Stack<Character> stack = new Stack<>();
for (char c : str.toCharArray()) stack.push(c);
char[] ch = new char[str.length()];
for (int i = 0; i < ch.length; i++) ch[i] = stack.pop();
return new String(ch);
}
public String reverseByStringBuilder(String str) {
if (str == null || str.length() <= 1) return str;
StringBuilder sb = new StringBuilder(str.length());
for (int i = str.length() - 1; i >= 0; i--) {
sb.append(str.charAt(i));
}
return sb.toString();
}
public String reverseByXor(String str) {
if (str == null || str.length() <= 1) return str;
char[] ch = str.toCharArray();
int len = ch.length;
for (int i = 0; i < len / 2; i++) {
ch[i] ^= ch[len - 1 - i];
ch[len - 1 - i] ^= ch[i];
ch[i] ^= ch[len - 1 - i];
}
return new String(ch);
}
a ^= b; b ^= a; a ^= b; 交換無需臨時變量public String reverseByRecursive(String str) {
if (str == null || str.length() == 0) return str;
if (str.length() == 1) return str;
return reverseByRecursive(str.substring(1)) + str.charAt(0);
}
substring 複製字符串,+ 拼接創建新對象public class Benchmark {
public static void main(String[] args) {
String s = "1234567890".repeat(1000); // 10000 字符
long start, end;
// 預熱
for (int i = 0; i < 10000; i++) reverseByArray(s);
// 數組法
start = System.nanoTime();
for (int i = 0; i < 100000; i++) reverseByArray(s);
end = System.nanoTime();
System.out.println("Array: " + (end - start) / 1e6 + " ms");
// StringBuilder
start = System.nanoTime();
for (int i = 0; i < 100000; i++) reverseByStringBuilder(s);
end = System.nanoTime();
System.out.println("StringBuilder: " + (end - start) / 1e6 + " ms");
// 棧
start = System.nanoTime();
for (int i = 0; i < 100000; i++) reverseByStack(s);
end = System.nanoTime();
System.out.println("Stack: " + (end - start) / 1e6 + " ms");
// 遞歸 (僅測試小字符串防 OOM)
String small = "12345";
start = System.nanoTime();
for (int i = 0; i < 10000; i++) reverseByRecursive(small);
end = System.nanoTime();
System.out.println("Recursive (small): " + (end - start) / 1e6 + " ms");
}
}
Array: 45 ms
StringBuilder: 52 ms
Stack: 180 ms
Recursive (small): 120 ms
| 算法 | 時間複雜度 | 空間複雜度 | 推薦指數 | 適用場景 |
|---|---|---|---|---|
| 數組雙指針 | O(n) | O(n) | ⭐⭐⭐⭐⭐ | 高性能要求、底層庫實現 |
| StringBuilder | O(n) | O(n) | ⭐⭐⭐⭐⭐ | 日常開發首選、可讀性好 |
| 棧 | O(n) | O(n) | ⭐⭐ | 教學、數據結構演示 |
| 位運算 XOR | O(n) | O(1) 額外 | ⭐ | 面試裝逼、嵌入式極限優化 |
| 遞歸 | O(n²) | O(n²) | ⭐ | 面試考察遞歸、函數式思維 |
String 不可變,反轉必產生新對象StringBuilder vs StringBuffer (線程安全開銷)substring 在 JDK 7+ 共享 char[] 但 JDK 8+ 複製,影響性能分析new StringBuilder(str).reverse().toString() 一行流式寫法