Python String Methods for Coding Interviews: The Complete Reference

- String immutability means every modification creates a new object; use
''.join(list)to build strings in O(n), not+=in a loop. len(s)is O(1) because CPython caches the length alongside the character buffer, so it's safe inside loops.s.split()with no argument collapses whitespace runs and strips ends;s.split(" ")does neither and produces empty strings between consecutive spaces.ord(c) - ord('a')maps lowercase letters to 0–25 for fixed-size frequency arrays, faster than a dict for small fixed alphabets.s.find(t)runs in O(n·m); for repeated or large-pattern matching, the rolling hash approach avoids the per-slice allocation.- The
isoperator compares object identity, not value — always compare strings with==in interviews, neveris. str.translatewithstr.maketransapplies a full character remapping in one O(n) pass, faster than chaining multiplereplacecalls.
You wrote result += ch in a loop. It passed on the examples. You felt good. Then the judge ran n=10,000 and your solution timed out. Welcome to Python strings.
This is the reference you keep open during practice: what each method does, what it costs, and where Python will confidently let you do something quadratic without a single complaint.
Strings Are Immutable. Everything Else Follows from That.
Python strings cannot be modified in place. Every operation that looks like a mutation actually returns a new string. s[0] = 'X' raises a TypeError. s = s + 'a' silently allocates a brand-new string, copies the old one in, and moves on with its life.
The practical consequence is brutal: building a string character by character with += in a loop is O(n²) total time. Each concatenation copies the growing prefix. The code looks innocent. Python says nothing. The judge disagrees.
# O(n²) - looks fine, is not fine result = "" for ch in chars: result += ch # O(n) - use this result = "".join(chars)
This is the single most common Python string bug in interviews. It runs fine on your test cases, which have six characters. It times out on the actual input, which has ten thousand.
To modify a string for real, convert to a list, edit in place, and join back.
s = list("hello") s[0] = "H" s = "".join(s)
Knowing ''.join() exists. Opening a loop with result += ch anyway.
Python String Methods: Time Complexity Reference
| Operation | Syntax | Time | Notes |
|---|---|---|---|
| Length | len(s) | O(1) | Cached by CPython |
| Index / slice | s[i], s[i:j] | O(1) / O(j-i) | Slice creates a new string |
| Concatenate | s + t | O(n+m) | Fine once; loop is O(n²) |
| Join | "".join(lst) | O(n) | Right way to build strings |
| Find / index | s.find(t) | O(n*m) | Naive; use for short patterns |
| Replace | s.replace(a, b) | O(n) | Replaces all occurrences |
| Split | s.split(sep) | O(n) | Returns list |
| Strip | s.strip() | O(n) | Strips both ends |
| Lower / upper | s.lower() | O(n) | New string |
| Starts / ends | s.startswith(t) | O(m) | m = len(t) |
| Count | s.count(t) | O(n*m) | Non-overlapping |
| Compare | s == t | O(min(n,m)) | Short-circuits on first diff |
| Reverse | s[::-1] | O(n) | New string |
| Sort chars | sorted(s) | O(n log n) | Returns list |
| ord / chr | ord(c), chr(i) | O(1) | Character to code point |
| Counter | Counter(s) | O(n) | Frequency map |
len(s) is O(1) because CPython stores the length alongside the character buffer. You can call it freely inside loops without guilt.
The Methods That Actually Win Interviews
split and join
Split tokenizes. Join reassembles. They pair naturally and together cover an embarrassing number of string interview problems.
words = s.split() # splits on any whitespace, strips leading/trailing words = s.split(",") # splits on literal comma s.split() # ["hello", "world"] from " hello world " s.split(" ") # ["", "", "hello", "", "", "world", "", ""] from same input
s.split() with no argument collapses runs of whitespace and strips the ends. s.split(" ") splits on exactly one space and produces empty strings for consecutive spaces. Problems that say "words separated by spaces" and then hide extra spaces in the test cases are testing whether you know this difference.
For reversing words in a sentence, one line:
return " ".join(reversed(s.split()))
strip, lstrip, rstrip
strip() removes leading and trailing characters from the given set (default: whitespace). It does not touch the middle. The argument is a character set, not a substring.
" hello ".strip() # "hello" "***hello***".strip("*") # "hello" "***hello***".lstrip("*") # "hello***" "abcba".strip("ab") # "c", strips any 'a' or 'b' from both ends
That last one bites people. strip("ab") does not mean "remove the substring ab." It means "remove any character that is a or b from both ends, repeatedly, until you hit something else."
startswith and endswith
Both accept a tuple of prefixes or suffixes, which saves you from writing an explicit loop:
s.startswith(("http://", "https://")) # True if either matches
replace and translate
replace(old, new) for simple swaps. For character-level remapping across multiple characters at once, str.maketrans plus translate is faster and cleaner:
table = str.maketrans("aeiou", "AEIOU") "hello".translate(table) # "hEllO" # Remove characters table = str.maketrans("", "", "aeiou") "hello".translate(table) # "hll"
translate applies the whole map in a single O(n) pass. Chaining replace calls runs once per substitution. For vowel problems and character-cleaning tasks, translate is the move.
isalpha, isdigit, isalnum, isspace
All O(n). The standard cleaning pattern:
clean = [c.lower() for c in s if c.isalnum()]
ord and chr Are Faster Than a Dict
Plenty of frequency and sliding-window problems reduce a character to an index into a 26-slot array. ord('a') is 97:
freq = [0] * 26 for c in s: freq[ord(c) - ord('a')] += 1
For lowercase-only problems this beats a Counter on constant factors, because array indexing is cheaper than hashing and the space is fixed at 26 slots. chr(ord('a') + i) converts back if you need to reconstruct a string from a frequency array.
Three Patterns String Problems Actually Test
Two Pointers: Palindrome
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
O(n) time, O(1) space. The slice s == s[::-1] also works but allocates O(n) extra space. If your interviewer asks about space complexity, you want the pointer version.
Sliding Window: Longest Substring Without Repeating Characters
def length_of_longest_substring(s: str) -> int: seen = {} left = 0 best = 0 for right, ch in enumerate(s): if ch in seen and seen[ch] >= left: left = seen[ch] + 1 seen[ch] = right best = max(best, right - left + 1) return best
The seen[ch] >= left check is the subtle part. Without it you would shrink the window for a character that already slid off the left side. This is the bug that makes the problem feel like it's working and then fails on "abba".
Frequency Map: Anagram Check
from collections import Counter def is_anagram(s: str, t: str) -> bool: return Counter(s) == Counter(t)
For a fixed character set like lowercase letters, comparing two 26-element lists beats Counter on constant factors. The sliding-window anagram pattern (LeetCode 438) extends this to find all anagram substrings.
The Pitfalls Nobody Warns You About
Python string docs, explaining is vs ==.
is vs ==
Python interns short strings and string literals. In a REPL:
"hello" is "hello" # True (interned)
Feels like equality. Is not equality. Always compare strings with ==. Using is is a bug that hides in local tests and surfaces only on real input, because the strings you build at runtime are not interned.
Slicing Is Not Free
s[i:j] allocates a new string of length j - i. In a tight loop that adds up fast. If you just need to compare, compare character by character or pass indices instead.
# Allocates a new string each iteration for i in range(n): if s[i:i+k] == pattern: ... # No allocation for i in range(n - k + 1): if all(s[i+j] == pattern[j] for j in range(k)): ...
For short patterns in an interview, the slice version is fine. For the rolling hash pattern, you avoid allocation entirely.
Unicode: len Counts Code Points, Not Bytes
s = "café" len(s) # 4 len(s.encode()) # 5 (UTF-8 encodes é as two bytes)
For pure ASCII problems this never bites you. If the problem says "characters" and the input contains non-ASCII, clarify upfront. Most LeetCode problems are ASCII-safe, but clarifying is always the right move.
Copy This Before Your Interview
# Reverse s[::-1] # Sort characters (returns list) sorted(s) # Repeat "-" * 20 # Frequency map Counter(s) # from collections [0] * 26 # for lowercase letters only # Check character type c.isalpha(), c.isdigit(), c.isalnum() # Case s.lower(), s.upper() # Tokenize s.split() # whitespace, strips ends s.split(",") # literal delimiter # Build from parts "".join(parts) "sep".join(parts) # Check prefix / suffix s.startswith("abc") s.endswith(("xyz", "zzz")) # Find substring (O(n*m)) s.find(t) # -1 if not found s.index(t) # raises ValueError if not found # Character to integer ord('a') # 97 chr(97) # 'a' ord(c) - ord('a') # 0-based index for lowercase # Strip whitespace s.strip() # Replace s.replace("old", "new")
What to Practice
Strings reward pattern practice more than volume. Five problems that build real intuition:
- LeetCode 3, Longest Substring Without Repeating Characters: canonical sliding window
- LeetCode 49, Group Anagrams: frequency maps and hashing
- LeetCode 5, Longest Palindromic Substring: expand-around-center vs DP
- LeetCode 76, Minimum Window Substring: sliding window with two counters
- LeetCode 187, Repeated DNA Sequences: rolling hash
Before any of those, make sure you can do the basics cold: reverse words in a sentence, check a palindrome with two pointers, build a frequency map. Those three cover 80% of the string subproblems embedded in harder questions.
String problems are deceptively easy to fumble live. The answer feels obvious until you start typing. Practice at SpaceComplexity with voice-based mock interviews where an AI interviewer pushes on your reasoning in real time, before you're doing it for the first time in an actual room.
Further Reading
- Python str documentation: official method reference with full signatures
- Python collections.Counter: Counter operations and use cases
- Unicode HOWTO, Python docs: how Python handles Unicode internally
- CPython string implementation: for the curious; shows why
lenis O(1) - GeeksforGeeks: Python String Methods: broad method catalogue with examples