💡 This approach uses recursion to swap characters from opposite ends, reinforcing understanding of recursion and two-pointer technique.
Intuition
Recursively swap the first and last characters, then recurse on the substring excluding those characters.
Algorithm
- Define a helper function with left and right pointers.
- If left >= right, return (base case).
- Swap characters at left and right.
- Recursively call helper with left+1 and right-1.
💡 This algorithm is elegant but uses call stack space, which may be a downside for large inputs.
def reverseString(s):
def helper(left, right):
if left >= right:
return
s[left], s[right] = s[right], s[left]
helper(left + 1, right - 1)
helper(0, len(s) - 1)
# Driver code
if __name__ == "__main__":
s = ['h','e','l','l','o']
reverseString(s)
print(s)
Line Notes
def helper(left, right):Define recursive function with two pointers
if left >= right:Base case: pointers have met or crossed, stop recursion
s[left], s[right] = s[right], s[left]Swap characters at current pointers
helper(left + 1, right - 1)Recurse inward by moving pointers
import java.util.Arrays;
public class ReverseString {
public static void reverseString(char[] s) {
helper(s, 0, s.length - 1);
}
private static void helper(char[] s, int left, int right) {
if (left >= right) return;
char temp = s[left];
s[left] = s[right];
s[right] = temp;
helper(s, left + 1, right - 1);
}
public static void main(String[] args) {
char[] s = {'h','e','l','l','o'};
reverseString(s);
System.out.println(Arrays.toString(s));
}
}
Line Notes
helper(s, 0, s.length - 1);Start recursion with pointers at array ends
if (left >= right) return;Base case to stop recursion when pointers meet or cross
char temp = s[left]; s[left] = s[right]; s[right] = temp;Swap characters at pointers
helper(s, left + 1, right - 1);Recursive call moving pointers inward
#include <iostream>
#include <vector>
using namespace std;
void helper(vector<char>& s, int left, int right) {
if (left >= right) return;
swap(s[left], s[right]);
helper(s, left + 1, right - 1);
}
void reverseString(vector<char>& s) {
helper(s, 0, s.size() - 1);
}
int main() {
vector<char> s = {'h','e','l','l','o'};
reverseString(s);
for (char c : s) cout << c;
cout << endl;
return 0;
}
Line Notes
if (left >= right) return;Base case to stop recursion when pointers meet or cross
swap(s[left], s[right]);Swap characters at current pointers
helper(s, left + 1, right - 1);Recursive call moving pointers inward
helper(s, 0, s.size() - 1);Initial call to start recursion
function reverseString(s) {
function helper(left, right) {
if (left >= right) return;
[s[left], s[right]] = [s[right], s[left]];
helper(left + 1, right - 1);
}
helper(0, s.length - 1);
}
// Test
const s = ['h','e','l','l','o'];
reverseString(s);
console.log(s);
Line Notes
function helper(left, right) {Define recursive helper with two pointers
if (left >= right) return;Base case to stop recursion when pointers meet or cross
[s[left], s[right]] = [s[right], s[left]];Swap characters at pointers using destructuring
helper(left + 1, right - 1);Recursive call moving pointers inward
TimeO(n)
SpaceO(n) due to recursion stack
Each recursive call processes one pair of characters, total n/2 calls, so linear time. Space is linear due to call stack.
💡 For n=100000, recursion depth is 50,000, which risks stack overflow in some languages.
Interview Verdict: Accepted but not recommended for large inputs
Recursion is elegant but can cause stack overflow; iterative two-pointer is safer.