題目: 編寫一個函數,輸入字符串,返回反轉後的字符串。要求原地修改輸入字符數組 (LeetCode 實際參數為 char[] s),空間複雜度 O(1)。
示例: ["h","e","l","l","o"] → ["o","l","l","e","h"]
left = 0,右指針 right = n - 1。left < right 時,交換 s[left] 和 s[right]。left++, right--,繼續直到相遇或錯過。class Solution {
public void reverseString(char[] s) {
int left = 0, right = s.length - 1;
while (left < right) {
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
left++;
right--;
}
}
}
class Solution {
public:
void reverseString(vector<char>& s) {
reverse(s.begin(), s.end()); //
}
};
class Solution:
def reverseString(self, s: List[str]) -> None:
s.reverse() # 列表原地反轉
# 或 s[:] = s[::-1] # 切片賦值 (原地修改列表內容)
var reverseString = function(s) {
let l = 0, r = s.length - 1;
while (l < r) {
[s[l], s[r]] = [s[r], s[l]]; // 解構賦值交換
l++; r--;
}
};
tmp 或解構暫存)。| 特性 | Java String | char[] / StringBuilder |
|---|---|---|
| 可變性 | 不可變 | 可變 |
| 反轉方式 | 新建對象 new StringBuilder(s).reverse().toString() | 原地交換 / reverse() |
| 空間 | O(n) | O(1) (原地) |
| LeetCode 344 參數 | ❌ 不是 String | ✅ 是 char[] |
注意:LeetCode 344 參數為char[] s(或List[Character]),**專門考察原地修改可變序列**。若輸入為 String,無法原地修改,必須返回新字符串,空間 O(n)。
// StringBuilder.reverse() 內部實現 (JDK 17+)
public StringBuilder reverse() {
boolean hasSurrogate = false;
int n = count - 1;
for (int i = 0; i < (count >> 1); i++) {
char c1 = value[i];
char c2 = value[n - i];
// 處理代理對 (Supplementary Characters, 4 bytes UTF-16)
if (Character.isHighSurrogate(c1)) {
hasSurrogate = true;
} else if (Character.isLowSurrogate(c2)) {
hasSurrogate = true;
}
value[i] = c2;
value[n - i] = c1;
}
if (hasSurrogate) {
// 代理對反轉需額外修正順序,防止非法 UTF-16 序列
// 簡化:重新編碼整個字符串 (較慢但正確)
// 實際 JDK 實現更精細
}
return this;
}
關鍵點: 反轉涉及 **UTF-16 代理對** 時,單純交換 char 會破壞補充字符 (Emoji、罕用漢字)。StringBuilder.reverse() 內部處理了這一邊界情況,而手寫 char[] 交換**不處理代理對**,若輸入含 Emoji 可能產生非法字符序列。LeetCode 344 測試用例通常僅含 BMP 字符 (ASCII/基本多文種平面),雙指針交換通用正確。
reverse, Python list.reverse, JS 解構交換, Java StringBuilder.reverse) 通常已優化處理邊界 (代理對、迭代器失效),工程首選。掌握雙指針原地交換模板、理解字符串不可變性與字符數組可變性的工程差異、知曉 UTF-16 代理對反轉陷阱,是基礎算法與字符處理工程化的雙重保障。