Top 15 String Coding Interview Problems: Ranked by What They Teach

- Frequency counting is the foundation: Valid Anagram's fixed-array pattern scales directly into Group Anagrams and Minimum Window Substring.
- Variable sliding window (LeetCode 3) is the frame every other sliding window problem reuses; learn it before anything else in that family.
- Fixed sliding window (LeetCode 438 and 567) introduces the incremental frequency-update trick that makes Minimum Window Substring tractable.
- Longest Repeating Character Replacement is the hardest medium in this list: its stale
max_countinvariant is counterintuitive but provably correct. - Expand around center requires handling odd and even palindromes separately; get it right on LeetCode 5 before attempting LeetCode 647.
- Edit Distance tests genuine DP fluency, not template recall; its
dp[i][j]transition is the backbone of spell checkers and diff tools.
String problems are what you feel good about at the start of prep and confused about at the end. You see Valid Anagram (Easy), sail through it, and think: I have this. Six problems later you are staring at Minimum Window Substring trying to figure out how you ended up here.
The gap between those two problems is five pattern families, internalized in sequence. This is that sequence. Fifteen problems, ordered by what each one teaches and why it hands you exactly what the next problem needs.
There Are Only Five Patterns. Learn Them in Order.
String problems cluster into five families:
- Frequency counting using hash maps over characters
- Two pointers converging on palindromes, partitioning, and cleanup
- Sliding window finding substrings that satisfy a constraint
- Expand around center for palindromic structures
- Dynamic programming for optimal subsequences and edit operations
Work through the fifteen problems below in this order. Skip around and you will spend twenty minutes on Minimum Window Substring with no idea what you are looking at.

1. Valid Anagram (LeetCode 242)
Pattern: Frequency counting | Difficulty: Easy
Two strings are anagrams if they contain the same characters with the same counts. Track frequencies in a 26-length array or a hash map, then compare.
This is the foundation. Every harder anagram problem (Group Anagrams, Minimum Window Substring) reuses this exact frequency-counting idea. Do it in O(n) with a fixed-size array. If you are reaching for sorted() here, that habit will cost you later.
def isAnagram(s: str, t: str) -> bool: if len(s) != len(t): return False count = [0] * 26 for c in s: count[ord(c) - ord('a')] += 1 for c in t: count[ord(c) - ord('a')] -= 1 if count[ord(c) - ord('a')] < 0: return False return True
2. Valid Palindrome (LeetCode 125)
Pattern: Two pointers | Difficulty: Easy
Filter to alphanumeric characters, then check whether the string reads the same forward and backward with two converging pointers. The annoying part: the input has spaces, punctuation, and mixed case. You clean it first, then you check.
This is the gateway to two-pointer thinking on strings. Palindromic Substrings (problem 9) and Longest Palindromic Substring (problem 8) build directly on this. Getting the cleanup step wrong here means making the same mistake twice, in a harder problem, under time pressure.
3. Longest Substring Without Repeating Characters (LeetCode 3)
Pattern: Sliding window (variable size) | Difficulty: Medium
The canonical sliding window introduction. A hash map tracks each character's most recent index. When you hit a character already in the window, jump the left pointer past its previous position. Track the maximum window size seen.
Once you can write this cleanly from memory, every other sliding window problem is a variation. Internalize the shrink step here, because sliding window mechanics will not wait for you to re-derive them when LeetCode 76 is on the screen.
def lengthOfLongestSubstring(s: str) -> int: char_index = {} left = 0 result = 0 for right, char in enumerate(s): if char in char_index and char_index[char] >= left: left = char_index[char] + 1 char_index[char] = right result = max(result, right - left + 1) return result
4. Group Anagrams (LeetCode 49)
Pattern: Frequency counting + hash map design | Difficulty: Medium
Group strings that are anagrams of each other. Use the sorted version of each string as the hash map key, or a tuple of character counts. Both approaches pass. The sorted key is O(k log k) per string. The count-tuple key is O(k).
This is where frequency counting meets key design. Knowing the tradeoff between sorted key and count tuple, and saying it out loud, is what turns "correct" into "impressive." Interviewers are writing notes the whole time. "Candidate considered O(k log k) vs O(k) key strategies" is a better note than "candidate got it."
5. Find All Anagrams in a String (LeetCode 438)
Pattern: Fixed sliding window | Difficulty: Medium
Find every starting index where a permutation of p appears in s. The window size is fixed at len(p). Slide it across s, updating character counts incrementally: add the entering character, remove the leaving one.
This is the fixed-window counterpart to problem 3's variable window. The key move is updating the frequency map in O(1) per step instead of rebuilding it. The have and need counter pattern appears here in embryonic form and matures fully in Minimum Window Substring.
6. Permutation in String (LeetCode 567)
Pattern: Fixed sliding window | Difficulty: Medium
Return true if any permutation of s1 appears as a substring of s2. Same structure as problem 5, different return type.
These two look nearly identical. That is the point. Doing both cements the pattern in a way that doing one twice does not, because the difference is in what you track and how you detect a match, not in the window mechanics themselves.
7. Longest Repeating Character Replacement (LeetCode 424)
Pattern: Sliding window with a counterintuitive invariant | Difficulty: Medium
Replace at most k characters in a window to make all characters the same. A window is valid when window_size - max_count_of_any_char <= k.
Here is where almost everyone stops and stares. max_count is never decremented when the window shrinks. You check your code three times. It still is not there. That feels like a bug.
It is not a bug.
You are only looking to grow the window beyond the current best. A stale max_count can keep you from shrinking when you theoretically could have, but that does not hurt the answer. You are not tracking the current window accurately. You are looking for a bigger valid window. The optimization is in not shrinking, not in bookkeeping.
This is the hardest medium-level sliding window problem because the invariant is counterintuitive. Understanding why a stale max is safe requires reasoning about what the window optimizes. That reasoning transfers to every tricky sliding window variation you will see after this.
8. Longest Palindromic Substring (LeetCode 5)
Pattern: Expand around center | Difficulty: Medium
For each position in the string, treat it as the center of a palindrome and expand outward while characters match. There are 2n - 1 centers: one per character, one per gap. Track the longest found.
The two-center trick (odd-length vs even-length palindromes) is where most implementations quietly break. Get it right here, and problem 9 takes five minutes. Manacher's algorithm does this in O(n), but you will not need to implement it in a standard interview round.
9. Palindromic Substrings (LeetCode 647)
Pattern: Expand around center | Difficulty: Medium
Count every palindromic substring. Same expand-around-center structure as problem 8. Instead of tracking the longest, increment a counter for every valid expansion step.
Frequently paired with problem 8 in interview sets. If you did not fully internalize the center loop in problem 8, this is where the gap shows up. Five minutes or forty-five minutes, depending on whether you solved 8 or just got 8.
10. Reverse Words in a String (LeetCode 151)
Pattern: String manipulation and edge case handling | Difficulty: Medium
Reverse the order of words, collapsing multiple spaces. In Python: ' '.join(s.split()). You are done.
In C++ or Java, you are not done. You need the manual approach: trim, split on whitespace, reverse the list. The logic is not hard. The failure mode is not anticipating leading spaces, trailing spaces, or five consecutive spaces where you expected one.
This problem tests language fluency as much as it tests logic. Knowing s.split() strips and splits in Python versus the manual two-pass approach in statically typed languages is the entire interview difference here.
11. Encode and Decode Strings (LeetCode 271)
Pattern: Protocol design | Difficulty: Medium
Design an encode function and a decode function. The catch: original strings can contain any character, including whatever delimiter you pick. Comma? The strings can have commas. Pipe? The strings can have pipes. Pick something exotic enough, and you have simply delayed the problem until someone finds a string that breaks it.
The fix is length-prefix encoding. Each string becomes {length}#{string}. So "hello" encodes as "5#hello". Decoding reads the length, jumps past the #, reads exactly that many characters, and repeats.
The point of this problem is the reasoning, not the code. Recognizing why naive delimiting breaks, landing on length-prefix encoding as the safe alternative, and explaining both clearly is exactly what interviewers are looking for. The implementation is almost trivial once you get there.
12. Word Break (LeetCode 139)
Pattern: Dynamic programming | Difficulty: Medium
Given a string and a word dictionary, return true if the string can be segmented into dictionary words. dp[i] is true if s[:i] can be formed from dictionary words. For each i, check every j < i where dp[j] is true and s[j:i] is in the dictionary. Time is O(n² × w) where w is average word length.
This is the bridge from string problems into DP. See the dynamic programming framework for the state setup and transition logic. Word Break shows up in tokenizers, parsers, and autocorrect. Getting the DP formulation right prepares you for an entire class of follow-up questions.
13. Minimum Window Substring (LeetCode 76)
Pattern: Sliding window (variable size, hard) | Difficulty: Hard
Find the smallest window in s containing all characters of t. Two pointers. Two frequency maps. A have counter tracks how many distinct required characters are fully satisfied. When have == need, the window is valid: record its length, then shrink from the left to search for something smaller.
This requires everything from problems 3 through 7: variable window, frequency counting, incremental updates, and multi-condition validity. Do this one last in the sliding window sequence. After it, the pattern is fully internalized.
def minWindow(s: str, t: str) -> str: if not t: return "" from collections import Counter count_t = Counter(t) window = {} have, need = 0, len(count_t) result, result_len = [-1, -1], float("inf") left = 0 for right, char in enumerate(s): window[char] = window.get(char, 0) + 1 if char in count_t and window[char] == count_t[char]: have += 1 while have == need: if right - left + 1 < result_len: result = [left, right] result_len = right - left + 1 window[s[left]] -= 1 if s[left] in count_t and window[s[left]] < count_t[s[left]]: have -= 1 left += 1 left, right = result return s[left:right + 1] if result_len != float("inf") else ""
14. Find the Index of the First Occurrence (LeetCode 28)
Pattern: String search (KMP awareness) | Difficulty: Easy/Medium
Return the index of the first occurrence of needle in haystack. The naive approach is O(nm). KMP does it in O(n + m) by precomputing a failure function that encodes how far to backtrack on a partial match.
You rarely need to implement KMP from scratch in an interview, but you should know it exists and why. Explaining the failure function concept, even without writing the code, signals that you understand string algorithms rather than just memorizing templates. That signal is worth more than it sounds.
15. Edit Distance (LeetCode 72)
Pattern: 2D dynamic programming | Difficulty: Hard
Find the minimum number of insert, delete, or replace operations to convert word1 into word2. This is the Levenshtein distance. Every spell checker, diff tool, and DNA alignment system runs some version of it. Autocorrect exists because someone solved this problem.
dp[i][j] is the minimum edits to convert word1[:i] to word2[:j]:
- Characters match:
dp[i][j] = dp[i-1][j-1] - Characters differ:
dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
The three cases correspond to delete from word1, insert into word1, and replace.
Getting the transition right requires a clear mental model of what each cell means. This is a genuine DP fluency signal, not pattern recognition. When an interviewer sees a clean solution with correct transitions and a clear verbal explanation of what dp[i][j] represents, they are not seeing someone who memorized an answer. They are seeing someone who understands the structure well enough to extend it.
String problems reward voice practice more than most categories. "Why does this window shrink?" and "why is this invariant safe?" are exactly the follow-up questions interviewers ask. SpaceComplexity runs you through these problems with rubric-based feedback on your reasoning, not just whether the code passes.
Further Reading
- LeetCode String Problems, the full problem bank, filterable by difficulty
- Knuth-Morris-Pratt Algorithm (Wikipedia), KMP failure function derivation and proof
- Levenshtein Distance (Wikipedia), edit distance and its real-world applications
- Manacher's Algorithm (GeeksforGeeks), O(n) palindrome finding, for reference beyond interviews
- String Hashing (cp-algorithms.com), polynomial rolling hash for advanced string matching