2109. Adding Spaces to a String
Problem Description
You are given a string s
(0-indexed) and an integer array spaces
(also 0-indexed) that contains indices where you need to insert spaces into the original string. Each space should be inserted before the character at the specified index.
For example:
- Input:
s = "EnjoyYourCoffee"
andspaces = [5, 9]
- The character at index 5 is
'Y'
and at index 9 is'C'
- We insert spaces before these characters
- Output:
"Enjoy Your Coffee"
The task is to return the modified string after all the spaces have been added at the specified positions.
Key points to understand:
- The indices in the
spaces
array refer to positions in the original strings
- Spaces are inserted before the character at each given index
- The
spaces
array is sorted in ascending order - You need to build and return the new string with all spaces properly inserted
Intuition
When we need to insert spaces at specific positions in a string, we face a challenge: as we insert spaces, the indices of subsequent characters shift. For instance, if we insert a space at position 5, the character that was originally at position 9 would now be at position 10.
To avoid this index-shifting problem, we can build the result string from scratch rather than trying to insert spaces into the existing string. The key insight is to traverse the original string character by character while keeping track of where spaces need to be inserted.
Since the spaces
array is sorted, we can use a pointer to track which space position we're currently looking for. As we iterate through each character in the original string:
- We check if the current index matches the next space position we need to handle
- If it matches, we add a space to our result before adding the current character
- We then move our space pointer forward to look for the next space position
This way, we only need to traverse the string once, checking at each position whether a space should be inserted. We're essentially merging two sequences: the characters from the original string and the spaces at their designated positions.
The beauty of this approach is that we don't need to worry about index adjustments or multiple string manipulations. We simply build the correct result in a single pass, making it both efficient and straightforward to implement.
Learn more about Two Pointers patterns.
Solution Approach
We implement a two-pointer approach to solve this problem efficiently in a single pass through the string.
Algorithm Steps:
-
Initialize data structures:
- Create an empty list
ans
to build the result string character by character - Set pointer
j = 0
to track our position in thespaces
array
- Create an empty list
-
Iterate through the original string:
- Use
enumerate(s)
to get both the indexi
and characterc
at each position - For each character position
i
:- Check if we need to insert a space: If
j < len(spaces)
(we haven't processed all spaces yet) ANDi == spaces[j]
(current position matches the next space position):- Append a space
' '
toans
- Increment
j
by 1 to move to the next space position
- Append a space
- Add the current character: Append
c
toans
- Check if we need to insert a space: If
- Use
-
Build and return the final string:
- Use
''.join(ans)
to convert the list of characters into the final string
- Use
Why this works:
- The pointer
j
ensures we process spaces in order since thespaces
array is sorted - By checking
j < len(spaces)
first, we avoid index out of bounds errors - We only traverse the string once, achieving
O(n)
time complexity wheren
is the length of the string - The space complexity is
O(n)
for storing the result
Example walkthrough with s = "EnjoyYourCoffee"
and spaces = [5, 9]
:
- At index 0-4: Add characters 'E', 'n', 'j', 'o', 'y' directly
- At index 5:
i == spaces[0]
, so add space then 'Y', incrementj
to 1 - At index 6-8: Add 'o', 'u', 'r' directly
- At index 9:
i == spaces[1]
, so add space then 'C', incrementj
to 2 - At index 10-14: Add remaining characters 'o', 'f', 'f', 'e', 'e'
- Result:
"Enjoy Your Coffee"
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example: s = "HelloWorld"
and spaces = [5]
Initial Setup:
- Original string:
"HelloWorld"
(length 10) - Space should be inserted before index 5 (character 'W')
- Initialize:
ans = []
,j = 0
Step-by-step iteration:
i | Character | j | spaces[j] | Action | ans after step |
---|---|---|---|---|---|
0 | 'H' | 0 | 5 | i ≠ 5, add 'H' | ['H'] |
1 | 'e' | 0 | 5 | i ≠ 5, add 'e' | ['H','e'] |
2 | 'l' | 0 | 5 | i ≠ 5, add 'l' | ['H','e','l'] |
3 | 'l' | 0 | 5 | i ≠ 5, add 'l' | ['H','e','l','l'] |
4 | 'o' | 0 | 5 | i ≠ 5, add 'o' | ['H','e','l','l','o'] |
5 | 'W' | 0 | 5 | i = 5, add ' ' then 'W', j→1 | ['H','e','l','l','o',' ','W'] |
6 | 'o' | 1 | - | j ≥ len(spaces), add 'o' | ['H','e','l','l','o',' ','W','o'] |
7 | 'r' | 1 | - | j ≥ len(spaces), add 'r' | ['H','e','l','l','o',' ','W','o','r'] |
8 | 'l' | 1 | - | j ≥ len(spaces), add 'l' | ['H','e','l','l','o',' ','W','o','r','l'] |
9 | 'd' | 1 | - | j ≥ len(spaces), add 'd' | ['H','e','l','l','o',' ','W','o','r','l','d'] |
Final Result: Join the list to get "Hello World"
The key insight: when we reach index 5, we first insert a space, then add 'W'. After processing this space position, we increment j
so we won't check for spaces[0] again. Since j
becomes 1 and len(spaces) = 1
, the condition j < len(spaces)
becomes false for all remaining iterations, so we simply add the rest of the characters without any more spaces.
Solution Implementation
1class Solution:
2 def addSpaces(self, s: str, spaces: List[int]) -> str:
3 """
4 Add spaces to a string at specified indices.
5
6 Args:
7 s: The input string
8 spaces: List of indices where spaces should be inserted
9
10 Returns:
11 Modified string with spaces inserted at specified positions
12 """
13 # List to build the result string efficiently
14 result = []
15
16 # Pointer to track current position in spaces array
17 space_index = 0
18
19 # Iterate through each character in the string with its index
20 for char_index, char in enumerate(s):
21 # Check if we need to insert a space at current position
22 if space_index < len(spaces) and char_index == spaces[space_index]:
23 result.append(' ')
24 space_index += 1 # Move to next space position
25
26 # Append the current character
27 result.append(char)
28
29 # Join all characters and spaces into final string
30 return ''.join(result)
31
1class Solution {
2 /**
3 * Adds spaces to a string at specified indices.
4 *
5 * @param s The original string to add spaces to
6 * @param spaces An array of indices where spaces should be inserted
7 * @return The modified string with spaces inserted at specified positions
8 */
9 public String addSpaces(String s, int[] spaces) {
10 // StringBuilder for efficient string concatenation
11 StringBuilder result = new StringBuilder();
12
13 // Index for tracking position in spaces array
14 int spaceIndex = 0;
15
16 // Iterate through each character in the original string
17 for (int charIndex = 0; charIndex < s.length(); charIndex++) {
18 // Check if current position matches the next space insertion point
19 if (spaceIndex < spaces.length && charIndex == spaces[spaceIndex]) {
20 // Insert a space at this position
21 result.append(' ');
22 // Move to the next space insertion index
23 spaceIndex++;
24 }
25
26 // Append the current character from the original string
27 result.append(s.charAt(charIndex));
28 }
29
30 // Convert StringBuilder to String and return
31 return result.toString();
32 }
33}
34
1class Solution {
2public:
3 string addSpaces(string s, vector<int>& spaces) {
4 // Result string to store the modified string with spaces
5 string result = "";
6
7 // Index pointer for the spaces array
8 int spaceIndex = 0;
9
10 // Iterate through each character in the original string
11 for (int i = 0; i < s.size(); ++i) {
12 // Check if current position matches the next space position
13 // Ensure we haven't exhausted all spaces positions
14 if (spaceIndex < spaces.size() && i == spaces[spaceIndex]) {
15 result += ' '; // Insert a space at this position
16 ++spaceIndex; // Move to the next space position
17 }
18
19 // Append the current character from original string
20 result += s[i];
21 }
22
23 return result;
24 }
25};
26
1/**
2 * Adds spaces to a string at specified indices
3 * @param s - The input string to add spaces to
4 * @param spaces - Array of indices where spaces should be inserted (sorted in ascending order)
5 * @returns The modified string with spaces inserted at specified positions
6 */
7function addSpaces(s: string, spaces: number[]): string {
8 // Array to build the result string character by character
9 const result: string[] = [];
10
11 // Index pointer for the spaces array
12 let spaceIndex: number = 0;
13
14 // Iterate through each character in the input string
15 for (let charIndex: number = 0; charIndex < s.length; charIndex++) {
16 // Check if current position matches the next space insertion point
17 if (spaceIndex < spaces.length && charIndex === spaces[spaceIndex]) {
18 // Insert a space at this position
19 result.push(' ');
20 // Move to the next space position
21 spaceIndex++;
22 }
23
24 // Add the current character from the original string
25 result.push(s[charIndex]);
26 }
27
28 // Join all characters and spaces into the final string
29 return result.join('');
30}
31
Time and Space Complexity
The time complexity is O(n + m)
, where n
is the length of the string s
and m
is the length of the array spaces
. This is because:
- We iterate through each character in the string
s
exactly once, which takesO(n)
time - For each character, we check if the current index matches a value in
spaces
, and we traverse thespaces
array at most once throughout the entire execution (using pointerj
), which contributesO(m)
time - The total time is
O(n) + O(m) = O(n + m)
The space complexity is O(n + m)
, where n
is the length of the string s
and m
is the length of the array spaces
. This is because:
- The
ans
list stores all characters from the original string (n
characters) plus all the spaces we need to insert (m
spaces in the worst case), resulting inO(n + m)
space - The final string created by
''.join(ans)
also requiresO(n + m)
space - Other variables like
i
,j
, andc
use constant spaceO(1)
- The total space complexity is
O(n + m)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Incorrectly Managing Indices After Inserting Spaces
The Problem: A common mistake is trying to insert spaces directly into the string while iterating, which causes index shifting. For example:
# INCORRECT approach
def addSpaces(s, spaces):
result = s
for index in spaces:
result = result[:index] + ' ' + result[index:]
return result
This fails because after inserting the first space, all subsequent indices in the original spaces
array become invalid. When you insert a space at position 5, the character that was at position 9 is now at position 10.
The Solution: Either adjust indices as you go (adding an offset for each inserted space) or use the two-pointer approach shown in the original solution that builds a new string from scratch.
Pitfall 2: String Concatenation Performance Issues
The Problem: Using string concatenation in a loop is inefficient in Python:
# INEFFICIENT approach
def addSpaces(s, spaces):
result = ""
space_index = 0
for i, char in enumerate(s):
if space_index < len(spaces) and i == spaces[space_index]:
result += " " # String concatenation
space_index += 1
result += char # String concatenation
return result
While this works correctly, string concatenation creates a new string object each time, leading to O(n²) time complexity for large strings.
The Solution: Use a list to collect characters and join them at the end, as shown in the original solution. This maintains O(n) time complexity since list append operations are O(1) amortized.
Pitfall 3: Forgetting Boundary Checks
The Problem:
Accessing spaces[space_index]
without checking if space_index < len(spaces)
first:
# INCORRECT - can cause IndexError
for i, char in enumerate(s):
if i == spaces[space_index]: # Dangerous! No bounds check
result.append(' ')
space_index += 1
result.append(char)
This throws an IndexError
when space_index
exceeds the length of the spaces
array.
The Solution:
Always check space_index < len(spaces)
before accessing spaces[space_index]
. The short-circuit evaluation of and
ensures the second condition is only checked if the first is true.
Which type of traversal does breadth first search do?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!