Skip to content
Codeloom
DSA

String Manipulation Tricks for Interviews

Essential string manipulation tricks — reverse words, reverse vowels, string rotation check, repeated substring pattern, multiply strings, and add binary.

·11 min read · By Codeloom
Intermediate 16 min read

What you'll learn

  • Reverse words in a string without extra libraries
  • Reverse only the vowels in a string using two pointers
  • Check if one string is a rotation of another in O(n)
  • Detect repeated substring patterns with the double-string trick
  • Multiply two large numbers represented as strings
  • Add two binary strings and handle carries correctly

Prerequisites

String manipulation

String manipulation problems are interview staples. They test whether you can think carefully about indexing, edge cases, and in-place operations. The problems in this post are not algorithmically deep — they rely on clever observations and clean implementation. That is exactly what makes them dangerous: small bugs hide in string code, and interviewers know it.

Problem 1: Reverse Words in a String

LeetCode 151. Given a string s, reverse the order of words. A word is a sequence of non-space characters. The result should have single spaces between words and no leading or trailing spaces.

The easy way

Python makes this trivial with split() and join():

def reverse_words(s: str) -> str:
    words = s.split()       # splits on any whitespace, removes empties
    return " ".join(words[::-1])

Time: O(n). Space: O(n) for the word list.

The interview way — in-place simulation

Interviewers often want you to do it without split. The classic approach for mutable strings (like char[] in Java or C):

  1. Reverse the entire string.
  2. Reverse each word individually.
  3. Clean up extra spaces.

In Python, we simulate with a list:

def reverse_words_manual(s: str) -> str:
    # Step 1: Convert to list and strip/collapse spaces
    chars = []
    i = 0
    n = len(s)
    while i {'<'} n:
        if s[i] != ' ':
            if chars and chars[-1] != ' ':
                pass
            elif chars:
                chars.append(' ')
            while i {'<'} n and s[i] != ' ':
                chars.append(s[i])
                i += 1
        else:
            i += 1

    # Step 2: Reverse entire list
    chars.reverse()

    # Step 3: Reverse each word
    start = 0
    for end in range(len(chars) + 1):
        if end == len(chars) or chars[end] == ' ':
            # Reverse chars[start:end]
            lo, hi = start, end - 1
            while lo {'<'} hi:
                chars[lo], chars[hi] = chars[hi], chars[lo]
                lo += 1
                hi -= 1
            start = end + 1

    return "".join(chars)

Walkthrough

For s = " the sky is blue ":

  • After space cleanup: ['t','h','e',' ','s','k','y',' ','i','s',' ','b','l','u','e']
  • After full reverse: ['e','u','l','b',' ','s','i',' ','y','k','s',' ','e','h','t']
  • After reversing each word: "blue is sky the".

Time: O(n). Space: O(n) because Python strings are immutable so we need a list.

Problem 2: Reverse Vowels of a String

LeetCode 345. Given a string s, reverse only the vowels.

Approach

Use two pointers, one from each end. Skip consonants. When both point to vowels, swap.

def reverse_vowels(s: str) -> str:
    vowels = set('aeiouAEIOU')
    chars = list(s)
    left, right = 0, len(chars) - 1

    while left {'<'} right:
        while left {'<'} right and chars[left] not in vowels:
            left += 1
        while left {'<'} right and chars[right] not in vowels:
            right -= 1
        if left {'<'} right:
            chars[left], chars[right] = chars[right], chars[left]
            left += 1
            right -= 1

    return "".join(chars)

Example

For s = "leetcode":

  • Vowels in order: e, e, o, e at indices 1, 2, 5, 7.
  • After reversing vowels: "leotcede".

Wait — let us trace carefully:

  • left=1 (e), right=7 (e) — swap (no change). left=2, right=6.
  • left=2 (e), right=5 (o) — but right=6 is d, skip to right=5 (o). Swap: positions 2 and 5. "leotcede".
  • left=3, right=4: t and c are consonants. Pointers cross. Done.
  • Answer: "leotcede".

Time: O(n). Space: O(n) for the character list (O(1) if mutable).

Problem 3: String Rotation Check

LeetCode 796. Given strings s1 and s2, return True if s2 is a rotation of s1.

The elegant trick

If s2 is a rotation of s1, then s2 must be a substring of s1 + s1. For example, "waterbottle" rotated to "erbottlewat" — and "erbottlewat" appears in "waterbottlewaterbottle".

def rotate_string(s1: str, s2: str) -> bool:
    if len(s1) != len(s2):
        return False
    return s2 in (s1 + s1)

Why it works

A rotation splits s1 at some index i: s1 = A + B, and the rotation is B + A. In s1 + s1 = A + B + A + B, the substring B + A always appears.

Time: O(n) — Python’s in uses an efficient substring search. Space: O(n) for the concatenated string.

Manual approach without concatenation

If the interviewer forbids the trick, you can check each rotation:

def rotate_string_manual(s1: str, s2: str) -> bool:
    if len(s1) != len(s2):
        return False
    n = len(s1)
    for i in range(n):
        # Check if rotating s1 by i positions gives s2
        match = True
        for j in range(n):
            if s1[(i + j) % n] != s2[j]:
                match = False
                break
        if match:
            return True
    return False

Time: O(n^2) worst case. Space: O(1).

Problem 4: Repeated Substring Pattern

LeetCode 459. Given a string s, check if it can be constructed by taking a substring of it and appending multiple copies of the substring.

Approach 1: The double-string trick

Similar to rotation: if s has a repeating pattern, then removing the first and last character of s + s and checking if s still appears will confirm it.

def repeated_substring_pattern(s: str) -> bool:
    doubled = (s + s)[1:-1]  # remove first and last char
    return s in doubled

Why it works

If s = "abcabc", then s + s = "abcabcabcabc". After removing first and last chars: "bcabcabcabc". The original s still appears at index 2. If s has no repeating unit, removing the boundary characters breaks all occurrences.

Approach 2: Divisor check

A repeating substring must have length d where d divides len(s) and d {'<'} len(s):

def repeated_substring_pattern_divisor(s: str) -> bool:
    n = len(s)
    for d in range(1, n // 2 + 1):
        if n % d == 0:
            pattern = s[:d]
            if pattern * (n // d) == s:
                return True
    return False

Example

For s = "abab":

  • d = 1: "a" * 4 = "aaaa" — no.
  • d = 2: "ab" * 2 = "abab" — yes.

Time: O(n * sqrt(n)) due to divisor checking. The double-string approach is O(n). Space: O(n).

Problem 5: Multiply Strings

LeetCode 43. Given two non-negative integers represented as strings, return their product as a string. You cannot convert to integers directly.

Approach

Simulate grade-school multiplication. For two numbers of length m and n, the product has at most m + n digits.

def multiply(num1: str, num2: str) -> str:
    if num1 == "0" or num2 == "0":
        return "0"

    m, n = len(num1), len(num2)
    result = [0] * (m + n)

    # Multiply digit by digit, right to left
    for i in range(m - 1, -1, -1):
        for j in range(n - 1, -1, -1):
            d1 = ord(num1[i]) - ord('0')
            d2 = ord(num2[j]) - ord('0')
            product = d1 * d2

            # Position in result array
            p1, p2 = i + j, i + j + 1
            total = product + result[p2]

            result[p2] = total % 10
            result[p1] += total // 10

    # Convert to string, skip leading zeros
    result_str = ""
    for digit in result:
        if not (result_str == "" and digit == 0):
            result_str += str(digit)

    return result_str if result_str else "0"

Walkthrough

For num1 = "123", num2 = "45":

  • 3 * 5 = 15 — put 5 at position 4, carry 1 to position 3.
  • 2 * 5 = 10 + 1 = 11 — put 1 at position 3, carry 1 to position 2.
  • 1 * 5 = 5 + 1 = 6 — put 6 at position 2.
  • 3 * 4 = 12 — add to positions 3 and 2.
  • 2 * 4 = 8 — add to positions 2 and 1.
  • 1 * 4 = 4 — add to positions 1 and 0.
  • Result array: [0, 5, 5, 3, 5]"5535".

Time: O(m * n). Space: O(m + n).

Problem 6: Add Binary

LeetCode 67. Given two binary strings a and b, return their sum as a binary string.

Approach

Process from right to left, adding digits and tracking the carry. This is the same algorithm as adding decimal numbers by hand.

def add_binary(a: str, b: str) -> str:
    result = []
    carry = 0
    i, j = len(a) - 1, len(b) - 1

    while i >= 0 or j >= 0 or carry:
        total = carry

        if i >= 0:
            total += int(a[i])
            i -= 1
        if j >= 0:
            total += int(b[j])
            j -= 1

        result.append(str(total % 2))
        carry = total // 2

    return "".join(reversed(result))

Example

For a = "1010", b = "1011":

    1 0 1 0
  + 1 0 1 1
  ---------
  1 0 1 0 1
  • Position 0: 0 + 1 = 1, carry 0.
  • Position 1: 1 + 1 = 2, write 0, carry 1.
  • Position 2: 0 + 0 + 1 = 1, carry 0.
  • Position 3: 1 + 1 = 2, write 0, carry 1.
  • Carry remains: write 1.
  • Answer: "10101".

Time: O(max(m, n)). Space: O(max(m, n)) for the result.

Generalized: Add strings of any base

The same pattern works for decimal addition (LeetCode 415) — just change % 2 to % 10 and // 2 to // 10:

def add_strings(num1: str, num2: str) -> str:
    result = []
    carry = 0
    i, j = len(num1) - 1, len(num2) - 1

    while i >= 0 or j >= 0 or carry:
        total = carry
        if i >= 0:
            total += ord(num1[i]) - ord('0')
            i -= 1
        if j >= 0:
            total += ord(num2[j]) - ord('0')
            j -= 1
        result.append(str(total % 10))
        carry = total // 10

    return "".join(reversed(result))

Complexity summary

ProblemTimeSpaceKey Trick
Reverse wordsO(n)O(n)Split + reverse, or reverse-all then reverse-each
Reverse vowelsO(n)O(n)Two pointers with vowel set
String rotationO(n)O(n)Check if s2 in s1+s1
Repeated patternO(n)O(n)Double-string with boundary removal
Multiply stringsO(m*n)O(m+n)Grade-school multiplication in array
Add binaryO(max(m,n))O(max(m,n))Right-to-left with carry

Common interview tips

1. Always clarify input constraints

  • Can the string be empty?
  • Does it contain only ASCII or Unicode?
  • Are there leading/trailing spaces?
  • Is the input always valid (e.g., valid binary for add binary)?

2. Use ord() instead of int() for character-to-digit

When you need digit values from string characters, ord(ch) - ord('0') is clearer about what you are doing and avoids implicit type conversions.

3. Build results in a list, join at the end

Never concatenate strings in a loop with +=. It creates a new string every time, making the total cost O(n^2). Always use a list and "".join() at the end.

# Bad: O(n^2)
result = ""
for ch in chars:
    result += ch

# Good: O(n)
parts = []
for ch in chars:
    parts.append(ch)
result = "".join(parts)

4. Edge cases that catch people

  • Empty strings.
  • Single-character strings.
  • Strings with all spaces (for reverse words).
  • Leading zeros (for multiply and add).
  • Strings of different lengths (for add binary).

Practice problems

  1. LeetCode 151 — Reverse Words in a String
  2. LeetCode 345 — Reverse Vowels of a String
  3. LeetCode 796 — Rotate String
  4. LeetCode 459 — Repeated Substring Pattern
  5. LeetCode 43 — Multiply Strings
  6. LeetCode 67 — Add Binary
  7. LeetCode 415 — Add Strings
  8. LeetCode 6 — Zigzag Conversion
  9. LeetCode 8 — String to Integer (atoi)
  10. LeetCode 28 — Find the Index of the First Occurrence in a String

Wrapping up

String manipulation problems reward careful implementation more than algorithmic brilliance. The key patterns — two pointers, right-to-left processing with carry, the double-string trick — are simple but powerful. Practice each one until the code flows without hesitation. In an interview, a clean solution to a “simple” string problem impresses more than a buggy attempt at something complex.