Hello! Welcome to your fifth lesson on core data structures.
In our last lesson, we compared arrays and linked lists, focusing on their performance trade-offs to help you decide when to use each one in an interview setting. You learned that the choice depends on the primary operations required, like random access versus frequent insertions/deletions.
Today, we dive into another ubiquitous sequential data type: strings. While they seem simple, string manipulation questions are a staple of technical interviews because they test your understanding of efficiency, edge cases, and common algorithmic patterns. Our goal is to implement common string manipulation operations and transformations efficiently. We'll cover the single most important concept about strings in many languages—immutability—and then apply patterns to solve classic interview problems.
1. The Immutability Trap and Efficient String Building
In Python (and Java), strings are immutable. This means that once a string is created, it cannot be changed. Any operation that appears to "modify" a string actually creates an entirely new string in memory. This has massive performance implications that interviewers love to test.
Consider building a string in a loop:
# Inefficient approach
my_string = ""
for char in list_of_characters:
my_string += char # This creates a NEW string in every iteration
This simple-looking code has a time complexity of ! With each concatenation, Python allocates new memory for a larger string and copies the contents of the old string and the new character.
To understand this critical concept and the correct, efficient alternative, watch the following short video segment.
Data Structure and Algorithm Patterns for LeetCode Interviews – Tutorial
The video 'Data Structure and Algorithm Patterns for LeetCode Interviews' from freeCodeCamp.org clearly explains the problem with string immutability and the efficient way to build strings.
Watch from 03:12 to 04:25. Pay close attention to the explanation of why string concatenation in a loop is O(N^2) and how using a list of characters and joining them at the end achieves O(N) complexity.
As the video explains, the correct way to build a string from multiple pieces is to append them to a list and then use the join method.
# Efficient approach
list_of_chars = ['a', 'b', 'c', 'd']
my_string = "".join(list_of_chars) # O(N)
# my_string is now "abcd"
The join method is efficient because it first calculates the total required memory, allocates it once, and then copies all characters. This is a fundamental pattern for any string-building task in an interview.
Test your understanding!
You are given a list of one million words. Your task is to concatenate them into a single string, with each word separated by a space. Which of the two Python snippets below is the correct, efficient way to do this, and why?
Snippet A:
result = ""
for word in words:
result += word + " "
Snippet B:
result = " ".join(words)
Show answer
Snippet B is the correct and efficient choice.
- Snippet A uses repeated string concatenation (
+=) inside a loop. As we've discussed, this is an operation, wherenis the total number of characters. For one million words, this would be extraordinarily slow. - Snippet B uses the
joinmethod, which is an operation. It computes the final string length, allocates memory once, and efficiently joins all the words. This is the idiomatic and performant way to accomplish this in Python.
2. Python's String Toolkit
Before tackling complex problems, let's quickly review the essential, built-in tools Python provides for string manipulation. Your familiarity with these is assumed in most interviews.

Most of these are self-explanatory, but let's focus on a few that are particularly useful in interviews.
Data Structure using Python - Interview Questions
The article 'Data Structure using Python - Interview Questions' from LearnToEarn Labs provides code examples for common string operations. We'll focus on slicing and the two-pointer reversal technique.
First, review the 'Explain how slicing works' section (Question 8) to see its syntax and use cases, including reversing a string. Then, examine the code in the 'Implement two-pointer approach to reverse a string' section (Question 11).
-
Slicing (
s[start:stop:step]): Incredibly powerful for extracting substrings. The expressions[::-1]is a Pythonic way to get a reversed copy of a string. While convenient, if an interviewer asks you to "reverse a string in-place," they are looking for the two-pointer method described in the article. -
Two-Pointer Reversal: This is a classic pattern. Because strings are immutable, you can't truly do it in-place. The standard approach is:
- Convert the string to a list of characters (which is mutable).
- Initialize two pointers,
leftat the start andrightat the end. - While
left < right, swap the characters at these pointers and move them towards the center. - Join the list back into a string.
This demonstrates that you can manually implement a core transformation without relying on a built-in shortcut, a common interview task.
3. Pattern 1: Two Pointers for Palindromes
The two-pointer technique is a high-ROI pattern for string and array problems. A classic application is checking for a valid palindrome.
Problem: Valid Palindrome
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. For example, "A man, a plan, a canal: Panama" is a palindrome.
This problem is a great test of the two-pointer pattern combined with character filtering and transformation. The following video provides a clear walkthrough.
Data Structure and Algorithm Patterns for LeetCode Interviews – Tutorial
Let's return to the freeCodeCamp.org video to see a step-by-step solution for the 'Valid Palindrome' problem using the two-pointer pattern.
Watch the segment from 22:54 to 25:06. Notice how the pointers are advanced to skip non-alphanumeric characters before any comparison is made. This filtering step is key.
The logic is a refinement of the two-pointer reversal:
- Initialize
leftandrightpointers at the beginning and end of the string. - In a loop (
while left < right):
a. Move theleftpointer forward until it lands on an alphanumeric character.
b. Move therightpointer backward until it lands on an alphanumeric character.
c. Compare the lowercase versions of the characters atleftandright. If they don't match, returnFalse.
d. Move both pointers inward:left += 1,right -= 1. - If the loop completes, return
True.
This approach is efficient, with time complexity as each character is visited at most once, and space complexity.
4. Pattern 2: Hash Maps for Character Counting
Many string problems revolve around character frequencies. The go-to data structure for this is a hash map (a dict in Python).
Problem: Valid Anagram
Given two strings s and t, return true if t is an anagram of s, and false otherwise. An anagram is a word formed by rearranging the letters of another, such as "cinema", formed from "iceman".
A simple solution is to sort both strings and check for equality (sorted(s) == sorted(t)). This works, but its time complexity is due to sorting. A more efficient, solution uses a hash map.
Data Structure using Python - Interview Questions
The 'Data Structure using Python' article provides a clean, hash-map-based implementation for checking anagrams.
Review the code under 'Check if two strings are anagrams using Python dictionaries' (Question 15). The logic involves building a frequency map from the first string and then decrementing counts using the second string.
The logic of the hash map approach is:
- If the strings have different lengths, they can't be anagrams, so return
False. - Create a frequency map (dictionary) of characters for the first string,
s. - Iterate through the second string,
t. For each character:
a. Decrement its count in the frequency map.
b. If a character is not in the map or its count becomes negative, the strings are not anagrams, so returnFalse. - If the loop completes, the strings are anagrams.
This pattern extends to many problems, such as finding the first non-repeating character or grouping anagrams from a list of words (see Question 20 in the same resource).

5. String Transformations: Run-Length Encoding
Finally, let's look at a common transformation problem: compressing a string.
Problem: Run-Length Encoding
Implement a function to perform basic string compression using the counts of repeated characters. For example, the string "aabcccccaaa" would become "a2b1c5a3".
This problem tests your ability to iterate carefully and manage state (count, prev_char).
Data Structure using Python - Interview Questions
The same article also has a great implementation for this problem.
Study the implementation for 'How do you implement run-length encoding of a string?' (Question 16). Pay attention to how it handles the transition when a character changes and how it appends the final count after the loop finishes.
The core logic is:
- Initialize an empty list for the results and set a
countto 1. - Iterate through the string from the second character.
- If the current character is the same as the previous one, increment
count. - If it's different, append the previous character and its count to the results list, then reset the
countto 1 and update the previous character. - Crucially, after the loop ends, append the last character and its count.
- Join the results list to form the final compressed string.
Conclusion
In this lesson, you've moved beyond treating strings as simple text and learned to analyze them through the lens of efficiency and algorithmic patterns—skills essential for your interviews.
Key Takeaways:
- Immutability is Key: Modifying strings in a loop leads to complexity. Always build strings by appending to a list and using
''.join()for an solution. - Master the Patterns: Many string problems are disguised array problems.
- Two-Pointers are excellent for problems involving symmetry or checking from both ends (e.g., palindromes, string reversal).
- Hash Maps are the optimal tool for problems based on character frequencies (e.g., anagrams).
- Practice Careful Iteration: Problems like run-length encoding require careful state management and handling of edge cases (like the end of the string).
In our next module, "High-ROI Interview Patterns: Pointers and Windows," we will formalize and expand on the two-pointer technique you saw today. We will also introduce its powerful sibling, the sliding window pattern, and apply them to solve a wide range of array and string problems.