LeetCode 917: Reverse Only Letters (Two Pointers with Non-Letter Skips)
LeetCode 917Two PointersStringToday we solve LeetCode 917 - Reverse Only Letters.
Source: https://leetcode.com/problems/reverse-only-letters/
English
Problem Summary
Given a string s, reverse only the English letters while keeping all non-letter characters in their original positions.
Key Insight
Use two pointers: l from the left and r from the right.
If s[l] is not a letter, move l forward. If s[r] is not a letter, move r backward. When both are letters, swap them and move both pointers.
Algorithm
1) Convert string to mutable char array.
2) Initialize l = 0, r = n - 1.
3) Skip non-letters on both sides.
4) Swap letters at l and r, then move inward.
5) Build string from the modified array.
Complexity Analysis
Each pointer moves at most n times.
Time: O(n).
Space: O(n) (for mutable char array in most languages).
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public String reverseOnlyLetters(String s) {
char[] a = s.toCharArray();
int l = 0, r = a.length - 1;
while (l < r) {
while (l < r && !Character.isLetter(a[l])) l++;
while (l < r && !Character.isLetter(a[r])) r--;
if (l < r) {
char t = a[l];
a[l] = a[r];
a[r] = t;
l++;
r--;
}
}
return new String(a);
}
}func reverseOnlyLetters(s string) string {
a := []byte(s)
l, r := 0, len(a)-1
isLetter := func(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
for l < r {
for l < r && !isLetter(a[l]) {
l++
}
for l < r && !isLetter(a[r]) {
r--
}
if l < r {
a[l], a[r] = a[r], a[l]
l++
r--
}
}
return string(a)
}class Solution {
public:
string reverseOnlyLetters(string s) {
int l = 0, r = (int)s.size() - 1;
auto isLetter = [](char c) {
return isalpha(static_cast<unsigned char>(c));
};
while (l < r) {
while (l < r && !isLetter(s[l])) ++l;
while (l < r && !isLetter(s[r])) --r;
if (l < r) {
swap(s[l], s[r]);
++l;
--r;
}
}
return s;
}
};class Solution:
def reverseOnlyLetters(self, s: str) -> str:
a = list(s)
l, r = 0, len(a) - 1
while l < r:
while l < r and not a[l].isalpha():
l += 1
while l < r and not a[r].isalpha():
r -= 1
if l < r:
a[l], a[r] = a[r], a[l]
l += 1
r -= 1
return "".join(a)var reverseOnlyLetters = function(s) {
const a = s.split('');
let l = 0, r = a.length - 1;
const isLetter = (c) => /[a-zA-Z]/.test(c);
while (l < r) {
while (l < r && !isLetter(a[l])) l++;
while (l < r && !isLetter(a[r])) r--;
if (l < r) {
[a[l], a[r]] = [a[r], a[l]];
l++;
r--;
}
}
return a.join('');
};中文
题目概述
给你一个字符串 s,要求只反转其中的英文字母,其他非字母字符的位置必须保持不变。
核心思路
使用双指针:l 从左向右,r 从右向左。
如果 s[l] 不是字母,就移动 l;如果 s[r] 不是字母,就移动 r。当两侧都指向字母时交换,然后双指针同时收缩。
算法步骤
1)将字符串转为可修改字符数组。
2)初始化 l = 0、r = n - 1。
3)两边跳过非字母字符。
4)交换左右字母并继续收缩。
5)最终把数组还原为字符串返回。
复杂度分析
两个指针总共各走不超过 n 步。
时间复杂度:O(n)。
空间复杂度:O(n)(多数语言使用字符数组)。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public String reverseOnlyLetters(String s) {
char[] a = s.toCharArray();
int l = 0, r = a.length - 1;
while (l < r) {
while (l < r && !Character.isLetter(a[l])) l++;
while (l < r && !Character.isLetter(a[r])) r--;
if (l < r) {
char t = a[l];
a[l] = a[r];
a[r] = t;
l++;
r--;
}
}
return new String(a);
}
}func reverseOnlyLetters(s string) string {
a := []byte(s)
l, r := 0, len(a)-1
isLetter := func(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
for l < r {
for l < r && !isLetter(a[l]) {
l++
}
for l < r && !isLetter(a[r]) {
r--
}
if l < r {
a[l], a[r] = a[r], a[l]
l++
r--
}
}
return string(a)
}class Solution {
public:
string reverseOnlyLetters(string s) {
int l = 0, r = (int)s.size() - 1;
auto isLetter = [](char c) {
return isalpha(static_cast<unsigned char>(c));
};
while (l < r) {
while (l < r && !isLetter(s[l])) ++l;
while (l < r && !isLetter(s[r])) --r;
if (l < r) {
swap(s[l], s[r]);
++l;
--r;
}
}
return s;
}
};class Solution:
def reverseOnlyLetters(self, s: str) -> str:
a = list(s)
l, r = 0, len(a) - 1
while l < r:
while l < r and not a[l].isalpha():
l += 1
while l < r and not a[r].isalpha():
r -= 1
if l < r:
a[l], a[r] = a[r], a[l]
l += 1
r -= 1
return "".join(a)var reverseOnlyLetters = function(s) {
const a = s.split('');
let l = 0, r = a.length - 1;
const isLetter = (c) => /[a-zA-Z]/.test(c);
while (l < r) {
while (l < r && !isLetter(a[l])) l++;
while (l < r && !isLetter(a[r])) r--;
if (l < r) {
[a[l], a[r]] = [a[r], a[l]];
l++;
r--;
}
}
return a.join('');
};
Comments