String Coding Interview Cheat Sheet: The One-Page Reference

June 19, 202611 min read
dsaalgorithmsinterview-prepleetcode
String Coding Interview Cheat Sheet: The One-Page Reference
TL;DR
  • String concatenation in a loop is O(n²): use a list + join in Python or StringBuilder in Java to avoid the quadratic trap
  • Two pointers handle palindromes and reversals; expand-around-center solves Longest Palindromic Substring in O(n²) time and O(1) space
  • Sliding window solves any "longest/shortest substring with constraint" problem in O(n) by expanding right and shrinking left on violation
  • Frequency counting solves anagram problems; a 26-element array beats a hash map for lowercase-only inputs and makes equality checks O(1)
  • Stack handles balanced brackets, nested structures, and anything requiring reverse-order character processing
  • s1.equals(s2) in Java is content comparison; == checks references and silently returns false for identical strings built separately
  • Know the ASCII anchors: 'a'=97, 'A'=65, '0'=48; map letters to 0-25 with ord(c) - ord('a')

Every string problem reduces to one of four patterns. This is the reference to skim in the hour before your interview, right after you've convinced yourself you definitely don't need to review strings because you've been writing code for years.

You do. Everyone does.

What Strings Actually Cost

Most engineers know strings are immutable. Fewer remember what that costs them until an interviewer says "by the way, your solution is O(n²)" while nodding very slowly.

Concatenation in a loop is O(n²). Each result = result + char allocates a new string and copies every character written so far. After n iterations you've done 1 + 2 + 3 + ... + n copies. That's O(n²). It's one of the most common string bugs in interviews because it doesn't look wrong and the tests still pass for small inputs. Your interviewer will not have small inputs.

OperationTime
LengthO(1)
Index access s[i]O(1)
Slice / substring s[i:j]O(j - i)
Find / indexOf (naive)O(n · m)
Concatenate with +O(n) per call
Build with list + joinO(n) total
Sort charactersO(n log n)
Convert to char arrayO(n)
# Wrong: O(n²), and you will be found out result = "" for char in s: result += char # Right: O(n), and you will be hired parts = [] for char in s: parts.append(char) result = "".join(parts)

In Java, use StringBuilder. Yes, it's verbose. Java is verbose. Make peace with it before the interview.

StringBuilder sb = new StringBuilder(); for (char c : s.toCharArray()) { sb.append(c); } String result = sb.toString();

The ASCII Numbers You'll Forget Under Pressure

Memorize the anchors. Derive the rest. Don't try to recall all of ASCII from scratch while someone is watching you write code.

  • 'a' = 97, 'z' = 122
  • 'A' = 65, 'Z' = 90
  • '0' = 48, '9' = 57
  • Lowercase to uppercase: subtract 32 (equivalently: XOR with 32)
  • Map 'a' through 'z' to 0-25: ord(c) - ord('a')

In Python: ord('a') returns 97, chr(97) returns 'a'. In Java: (int) 'a' returns 97, (char) 97 returns 'a'. In JavaScript: 'a'.charCodeAt(0) returns 97, String.fromCharCode(97) returns 'a'.

The only reason to know these cold is that the moment you can't remember whether 'A' is 65 or 67, you'll burn two minutes second-guessing yourself on a problem you already know how to solve.

Pattern 1: Two Pointers for Palindromes and Reversals

Left pointer at the start, right at the end, move toward the center. Stop when they cross.

def is_palindrome(s: str) -> bool: left, right = 0, len(s) - 1 while left < right: if s[left] != s[right]: return False left += 1 right -= 1 return True

The pointer doesn't have to move one step at a time. When a problem says "ignore non-alphanumeric characters," advance each pointer past anything that doesn't qualify:

while left < right and not s[left].isalnum(): left += 1 while left < right and not s[right].isalnum(): right -= 1

For "Longest Palindromic Substring," use expand-around-center instead: for each index, expand outward while characters match. Run once for odd-length palindromes (center = single character) and once for even-length (center = pair). O(n²) time, O(1) space. It's one of the few times O(n²) is the expected answer.

Pattern 2: Sliding Window for Substring Constraints

Use a sliding window when the problem asks for the longest or shortest substring satisfying some condition on its contents. The window expands until it breaks the rule, then shrinks until it doesn't. Repeat.

The invariant is always the same: expand the right pointer on every iteration, shrink the left pointer when the window violates the constraint.

def length_of_longest_substring(s: str) -> int: seen = {} left = 0 result = 0 for right, char in enumerate(s): if char in seen and seen[char] >= left: left = seen[char] + 1 seen[char] = right result = max(result, right - left + 1) return result

For "Minimum Window Substring," maintain a frequency map of what you still need. When all required characters are present in the window, try shrinking from the left. The window bounds are [left, right] and its length is right - left + 1. Most sliding window problems run in O(n) time, which is the satisfying part after the setup feels complicated.

Pattern 3: Frequency Counting for Anagrams

When order doesn't matter but count does, reach for a frequency map. When the input is constrained to lowercase English letters, use an array of 26 instead of a hash map. It sounds like a micro-optimization. It is not.

def is_anagram(s: str, t: str) -> bool: if len(s) != len(t): return False count = [0] * 26 for a, b in zip(s, t): count[ord(a) - ord('a')] += 1 count[ord(b) - ord('a')] -= 1 return all(x == 0 for x in count)

The 26-element array is not just a micro-optimization. Checking whether two frequency arrays are equal takes O(26) = O(1). With a hash map, comparing equality is O(k) where k is the number of distinct characters. The array also sidesteps hash collision concerns entirely. Use the array whenever the alphabet is bounded.

For "Group Anagrams," the canonical key is the sorted word. All anagrams share the same sorted form. You can also key by a 26-element tuple if you want to avoid the O(k log k) sort, but sorted is readable and that matters during an interview.

from collections import defaultdict def group_anagrams(strs: list[str]) -> list[list[str]]: groups = defaultdict(list) for word in strs: groups[tuple(sorted(word))].append(word) return list(groups.values())

Sliding window plus frequency map together solve "Find All Anagrams in a String" (LeetCode 438): maintain a 26-element frequency delta, and check if it's all zeros as you slide a fixed-width window across the text.

Pattern 4: Stack for Brackets and Nesting

When the problem involves balanced pairs, nested structures, or processing characters in reverse order, use a stack. The instinct is usually right.

def is_valid(s: str) -> bool: stack = [] pairs = {')': '(', '}': '{', ']': '['} for c in s: if c in '({[': stack.append(c) elif not stack or stack[-1] != pairs[c]: return False else: stack.pop() return not stack

The not stack check at the end catches unclosed brackets, which many implementations forget. Getting the early-return cases right is what separates a good answer from a great one, and interviewers notice. The same structure handles "Decode String" (LeetCode 394), "Remove All Adjacent Duplicates" (LeetCode 1047), and "Basic Calculator" (LeetCode 224). One template, many problems.

The Java Bug That Kills Every Other Candidate

These come up less than the patterns above, but when they do, they cost you.

Java: s1.equals(s2) for content comparison. s1 == s2 checks reference equality and will return false for two independently constructed strings with identical content. This is probably the most common Java bug in interviews, and it's the kind that passes your own mental trace because both strings "look the same" while you write the code.

Python: s1 == s2 compares content. s1 is s2 checks identity and exploits string interning, which only applies reliably to short, compile-time strings. Always use ==.

JavaScript/TypeScript: === works correctly for string content. Avoid == with strings. No surprises at the operator level, but remember that typeof null === "object" while typeof "hello" === "string". JavaScript contains multitudes.

Tom and Jerry, the 'debugging' cat chasing a mouse labeled 'the bug' You, hunting the Java == bug through a 400-line solution that "should" be working.

When to Mention KMP (Without Implementing It)

Most interviewers won't ask you to implement Knuth-Morris-Pratt from memory. If you get "implement strStr()" or "find all occurrences of a pattern," start with the O(n·m) brute-force two-pointer approach.

Saying "this can be done in O(n+m) with KMP by precomputing a failure function" scores the same points as implementing it, without the implementation risk. The same applies to Rabin-Karp with rolling hash. Python's in operator and Java's indexOf both use optimized algorithms under the hood, so for interview problems with n and m up to 10^4, the naive approach won't time out.

If you want to actually know how KMP works: the failure function stores, for each position in the pattern, the length of the longest proper prefix that is also a suffix. This lets the search avoid re-examining characters it already matched. See Knuth-Morris-Pratt on Wikipedia for the clean derivation.

Edge Cases That Get Missed

The interviewer has seen hundreds of solutions. They know exactly which edge cases people skip.

  • Empty string: "" is falsy in Python, not in Java or JavaScript
  • Single character: makes palindrome checks and two-pointer problems trivially true
  • All same characters: frequency maps still work, but the result is often a special case worth stating
  • Leading and trailing spaces: s.strip() in Python, s.trim() in Java/JavaScript
  • Mixed case: always ask whether 'A' and 'a' should be treated as equal before you code
  • Unicode: len("😀") = 1 in Python 3 (counts code points), but "😀".length = 2 in JavaScript (counts UTF-16 code units). Almost no interview problem exercises this, but worth knowing

The interviewer asking you to handle non-ASCII input is almost always testing whether you know to ask. State what you're assuming and move on. "I'll assume ASCII lowercase for now, should I handle Unicode?" takes five seconds and makes you look thoughtful instead of oblivious.

Language Quick Reference

s[::-1] # reverse s.split() # split on whitespace, handles runs ''.join(lst) # build string from list s.lower() / s.upper() s.strip() / s.lstrip() / s.rstrip() s.isalpha() / s.isdigit() / s.isalnum() ord('a') == 97 chr(97) == 'a' s.count('x') # occurrences of substring

JavaScript / TypeScript

s.split('') // to char array arr.join('') // back to string s.slice(i, j) // [i, j) s.includes('sub') s.toLowerCase() s.trim() s.charCodeAt(i) String.fromCharCode(n) Array.from(s) // handles multi-code-unit chars correctly

String Interview Problems That Appear Most

ProblemPatternTimeSpace
Valid Palindrome (LC 125)Two pointersO(n)O(1)
Longest Substring Without Repeat (LC 3)Sliding windowO(n)O(min(n,m))
Minimum Window Substring (LC 76)Sliding window + freqO(n+m)O(m)
Valid Anagram (LC 242)Frequency countO(n)O(1)
Group Anagrams (LC 49)Sort as keyO(nk log k)O(nk)
Valid Parentheses (LC 20)StackO(n)O(n)
Longest Palindromic Substring (LC 5)Expand around centerO(n²)O(1)
Find All Anagrams in a String (LC 438)Sliding window + freqO(n+m)O(1)
Implement strStr() (LC 28)Two pointers / KMPO(n·m) / O(n+m)O(1) / O(m)
Encode and Decode Strings (LC 271)Length prefixO(n)O(n)

Tom in a tuxedo labeled 'The technical interview' vs Tom beaten up labeled 'The actual job' Knowing the patterns is the prerequisite. The actual interview requires explaining them out loud under pressure.

For the full breakdown of what each problem teaches and how to order them by difficulty, the top string interview problems guide goes problem by problem.

Knowing the patterns is the prerequisite. Performing them while thinking out loud, explaining tradeoffs, and handling follow-up questions is what actually separates offers from rejections. That's a different skill, and it takes practice under realistic conditions. SpaceComplexity runs voice-based mock interviews with rubric-based feedback on the same dimensions Google and Meta score: communication, problem-solving, code quality, and verification. If the patterns feel solid but the interviews don't, that's the gap.

Further Reading