1592. Rearrange Spaces Between Words
Problem Description
You are given a string text
that contains words separated by spaces. Each word consists of one or more lowercase English letters, and words are separated by at least one space. The string is guaranteed to contain at least one word.
Your task is to rearrange the spaces in the string so that:
- The spaces between adjacent words are distributed as equally as possible
- The number of spaces between each pair of adjacent words should be maximized and equal
- If the total number of spaces cannot be divided equally among all gaps between words, the extra spaces should be placed at the end of the string
- The length of the returned string must be the same as the original
text
For example, if you have 3 words and 6 spaces total, you would place 3 spaces between the first and second word, 3 spaces between the second and third word, and 0 extra spaces at the end. If you have 3 words and 7 spaces total, you would place 3 spaces between each pair of adjacent words (using 6 spaces total) and put the remaining 1 space at the end.
Special case: If there is only one word in the text, all spaces should be placed at the end of that word.
The goal is to return the modified string with the rearranged spaces.
Intuition
To solve this problem, we need to think about what information we need and how to distribute the spaces evenly.
First, we need to know two key pieces of information:
- How many total spaces are in the original string?
- How many words are there?
Once we have the words separated, we can figure out how many gaps exist between words. If we have n
words, there are n - 1
gaps between them (like fence posts and fence sections).
The core mathematical insight is that we want to distribute all available spaces as evenly as possible among these gaps. This is a classic division problem: if we have spaces
total spaces and n - 1
gaps, then each gap should ideally get spaces / (n - 1)
spaces.
But what if the spaces don't divide evenly? For example, if we have 7 spaces and 2 gaps, each gap would get 3 spaces (7 ÷ 2 = 3 with remainder 1). The remainder tells us how many extra spaces we have that couldn't be distributed evenly - these go at the end of the string.
This naturally leads us to use integer division with remainder (divmod
in Python), which gives us both:
- The quotient: number of spaces to put between each pair of words
- The remainder: extra spaces to append at the end
The edge case of having only one word is straightforward - with no gaps between words, all spaces must go at the end.
The solution elegantly handles the distribution by using the join operation with the calculated number of spaces, then appending any leftover spaces at the end.
Solution Approach
Following the intuition, let's implement the solution step by step:
-
Count the total spaces: We use
text.count(" ")
to count all space characters in the original string. This gives us the total number of spaces we need to redistribute. -
Extract the words: We use
text.split()
which automatically splits the string by any whitespace and removes empty strings, giving us a clean list of words. For example,"hello world"
becomes["hello", "world"]
. -
Handle the edge case: If there's only one word (
len(words) == 1
), we simply return that word followed by all the spaces:words[0] + " " * spaces
. -
Calculate space distribution: For multiple words, we need to distribute spaces among
len(words) - 1
gaps. We usedivmod(spaces, len(words) - 1)
which returns:cnt
: The number of spaces to place between each pair of adjacent words (quotient)mod
: The number of leftover spaces to place at the end (remainder)
-
Reconstruct the string: We use two operations:
(" " * cnt).join(words)
: Creates a string withcnt
spaces between each word. Thejoin
method inserts the separator (which iscnt
spaces) between each element in thewords
list.+ " " * mod
: Appends the remaining spaces at the end.
For example, if we have text = " this is a sentence "
with 9 spaces and 4 words:
- Number of gaps = 4 - 1 = 3
divmod(9, 3)
returnscnt = 3, mod = 0
- Result:
"this is a sentence"
(3 spaces between each word, 0 at the end)
This approach ensures we maximize and equalize the spaces between words while maintaining the original string length.
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 the solution with a concrete example: text = " hello world code "
Step 1: Count total spaces
- Count all spaces in the string:
" hello world code "
has 2 + 4 + 2 + 2 = 10 spaces total
Step 2: Extract words
- Split the text to get words:
["hello", "world", "code"]
- We have 3 words
Step 3: Check if it's a single word
- Since we have 3 words (not 1), we proceed to distribute spaces
Step 4: Calculate space distribution
- Number of gaps between words = 3 - 1 = 2 gaps
- Use
divmod(10, 2)
:- Quotient (cnt) = 5 → each gap gets 5 spaces
- Remainder (mod) = 0 → no extra spaces for the end
Step 5: Reconstruct the string
- Join words with 5 spaces:
"hello" + " " + "world" + " " + "code"
- Add remainder spaces at end: 0 spaces
- Final result:
"hello world code"
The spaces are now evenly distributed with 5 spaces between each pair of words.
Another example with remainder: text = " a b c "
(5 spaces total, 3 words)
- Words:
["a", "b", "c"]
- Gaps: 3 - 1 = 2
divmod(5, 2)
→ cnt = 2, mod = 1- Result:
"a b c "
(2 spaces between words, 1 extra space at the end)
Edge case - single word: text = " hello "
(7 spaces, 1 word)
- Words:
["hello"]
- Since there's only 1 word, return:
"hello "
(word + all 7 spaces at the end)
Solution Implementation
1class Solution:
2 def reorderSpaces(self, text: str) -> str:
3 # Count total number of spaces in the text
4 total_spaces = text.count(" ")
5
6 # Split text into words (automatically removes all spaces)
7 words = text.split()
8
9 # Special case: if only one word exists, append all spaces at the end
10 if len(words) == 1:
11 return words[0] + " " * total_spaces
12
13 # Calculate spaces between words and remaining spaces
14 # spaces_between: number of spaces to place between each pair of words
15 # remaining_spaces: leftover spaces to append at the end
16 spaces_between, remaining_spaces = divmod(total_spaces, len(words) - 1)
17
18 # Join words with calculated spaces between them and append remaining spaces
19 return (" " * spaces_between).join(words) + " " * remaining_spaces
20
1class Solution {
2 public String reorderSpaces(String text) {
3 // Count total number of spaces in the text
4 int totalSpaces = 0;
5 for (char character : text.toCharArray()) {
6 if (character == ' ') {
7 totalSpaces++;
8 }
9 }
10
11 // Extract all words from the text (removing leading/trailing spaces and splitting by spaces)
12 String[] words = text.trim().split("\\s+");
13
14 // Special case: if there's only one word, append all spaces at the end
15 if (words.length == 1) {
16 return words[0] + " ".repeat(totalSpaces);
17 }
18
19 // Calculate spaces to distribute between words and remaining spaces
20 int spacesBetweenWords = totalSpaces / (words.length - 1);
21 int remainingSpaces = totalSpaces % (words.length - 1);
22
23 // Build the result string
24 StringBuilder result = new StringBuilder();
25 for (int i = 0; i < words.length; i++) {
26 // Append current word
27 result.append(words[i]);
28
29 // Add spaces between words (not after the last word)
30 if (i < words.length - 1) {
31 result.append(" ".repeat(spacesBetweenWords));
32 }
33 }
34
35 // Append any remaining spaces at the end
36 result.append(" ".repeat(remainingSpaces));
37
38 return result.toString();
39 }
40}
41
1class Solution {
2public:
3 string reorderSpaces(string text) {
4 // Count total number of spaces in the text
5 int spaceCount = ranges::count(text, ' ');
6
7 // Extract all words from the text
8 vector<string> words = extractWords(text);
9
10 // Special case: if there's only one word, append all spaces at the end
11 if (words.size() == 1) {
12 return words[0] + string(spaceCount, ' ');
13 }
14
15 // Calculate spaces between words and remaining spaces
16 int spacesBetweenWords = spaceCount / (words.size() - 1);
17 int remainingSpaces = spaceCount % (words.size() - 1);
18
19 // Join words with calculated spaces between them
20 string result = joinWords(words, string(spacesBetweenWords, ' '));
21
22 // Append remaining spaces at the end
23 result += string(remainingSpaces, ' ');
24
25 return result;
26 }
27
28private:
29 // Extract all non-empty words from the input text
30 vector<string> extractWords(const string& text) {
31 vector<string> words;
32 istringstream stream(text);
33 string word;
34
35 // Read words separated by whitespace
36 while (stream >> word) {
37 words.push_back(word);
38 }
39
40 return words;
41 }
42
43 // Join words with the specified separator between them
44 string joinWords(const vector<string>& words, const string& separator) {
45 ostringstream result;
46
47 for (size_t i = 0; i < words.size(); ++i) {
48 result << words[i];
49
50 // Add separator between words (not after the last word)
51 if (i < words.size() - 1) {
52 result << separator;
53 }
54 }
55
56 return result.str();
57 }
58};
59
1/**
2 * Reorders spaces in a text string by evenly distributing them between words
3 * and placing any remaining spaces at the end
4 * @param text - The input string containing words and spaces
5 * @returns The reordered string with spaces evenly distributed
6 */
7function reorderSpaces(text: string): string {
8 // Count total number of spaces in the text
9 const totalSpaces: number = (text.match(/ /g) || []).length;
10
11 // Extract all non-empty words from the text
12 const words: string[] = text.split(/\s+/).filter(Boolean);
13
14 // Special case: if there's only one word, append all spaces to the end
15 if (words.length === 1) {
16 return words[0] + ' '.repeat(totalSpaces);
17 }
18
19 // Calculate spaces to place between each pair of words
20 const spacesBetweenWords: number = Math.floor(totalSpaces / (words.length - 1));
21
22 // Calculate remaining spaces to append at the end
23 const remainingSpaces: number = totalSpaces % (words.length - 1);
24
25 // Join words with calculated spaces between them
26 const reorderedText: string = words.join(' '.repeat(spacesBetweenWords));
27
28 // Append any remaining spaces to the end and return
29 return reorderedText + ' '.repeat(remainingSpaces);
30}
31
Time and Space Complexity
The time complexity is O(n)
, where n
represents the length of the string text
. This is because:
text.count(" ")
traverses the entire string once:O(n)
text.split()
traverses the entire string to identify and extract words:O(n)
(" " * cnt).join(words)
creates a new string by joining words, which in the worst case processes all characters:O(n)
- String concatenation at the end with
" " * mod
is at mostO(n)
sincemod < n
The space complexity is O(n)
, where n
represents the length of the string text
. This is because:
words
list stores all the words from the original string, which in total can be at mostn
characters:O(n)
- The output string created by
join()
and concatenation operations requires space proportional to the input string length:O(n)
- Temporary strings created during operations like
" " * cnt
are bounded byO(n)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding the Space Distribution Logic
A common mistake is thinking that extra spaces should be distributed among the gaps rather than placed at the end. For instance, if you have 3 words and 7 spaces, you might incorrectly try to put 3 spaces after the first word, 2 after the second, and 2 at the end. However, the problem requires equal distribution with leftovers at the end (3 spaces between each pair, 1 at the end).
Incorrect approach:
# Wrong: Trying to distribute extra spaces among gaps
gaps = len(words) - 1
base_spaces = total_spaces // gaps
extra = total_spaces % gaps
# Then attempting to add extra spaces to first few gaps
Correct approach:
# Right: Equal spaces between all gaps, remainder at end
spaces_between, remaining_spaces = divmod(total_spaces, len(words) - 1)
2. Division by Zero When Only One Word Exists
If there's only one word in the text, calculating total_spaces // (len(words) - 1)
would cause a division by zero error. This is why the edge case check is crucial.
Problematic code:
def reorderSpaces(self, text: str) -> str:
total_spaces = text.count(" ")
words = text.split()
# This will crash if len(words) == 1
spaces_between = total_spaces // (len(words) - 1) # Division by zero!
Solution: Always check for the single-word case before performing division:
if len(words) == 1:
return words[0] + " " * total_spaces
3. Using Wrong String Methods for Counting or Splitting
Some might try to manually parse the string or use incorrect methods that don't handle multiple consecutive spaces properly.
Incorrect approaches:
# Wrong: This won't handle multiple consecutive spaces correctly words = text.split(" ") # Creates empty strings for consecutive spaces # Wrong: Manual parsing that's error-prone words = [] current_word = "" for char in text: if char != " ": current_word += char elif current_word: words.append(current_word) current_word = ""
Correct approach:
# Right: split() without arguments handles any whitespace correctly words = text.split() # Automatically removes all spaces and empty strings
4. Forgetting to Maintain Original String Length
A critical requirement is that the output string must have the same length as the input. Some solutions might forget to account for all spaces or accidentally change the total length.
Verification tip:
Always verify that len(result) == len(text)
in your solution. The provided solution maintains this by using all counted spaces exactly once - either between words or at the end.
What's the output of running the following function using input 56
?
1KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13 def dfs(path, res):
14 if len(path) == len(digits):
15 res.append(''.join(path))
16 return
17
18 next_number = digits[len(path)]
19 for letter in KEYBOARD[next_number]:
20 path.append(letter)
21 dfs(path, res)
22 path.pop()
23
24 res = []
25 dfs([], res)
26 return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2 '2', "abc".toCharArray(),
3 '3', "def".toCharArray(),
4 '4', "ghi".toCharArray(),
5 '5', "jkl".toCharArray(),
6 '6', "mno".toCharArray(),
7 '7', "pqrs".toCharArray(),
8 '8', "tuv".toCharArray(),
9 '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13 List<String> res = new ArrayList<>();
14 dfs(new StringBuilder(), res, digits.toCharArray());
15 return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19 if (path.length() == digits.length) {
20 res.add(path.toString());
21 return;
22 }
23 char next_digit = digits[path.length()];
24 for (char letter : KEYBOARD.get(next_digit)) {
25 path.append(letter);
26 dfs(path, res, digits);
27 path.deleteCharAt(path.length() - 1);
28 }
29}
30
1const KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13 let res = [];
14 dfs(digits, [], res);
15 return res;
16}
17
18function dfs(digits, path, res) {
19 if (path.length === digits.length) {
20 res.push(path.join(''));
21 return;
22 }
23 let next_number = digits.charAt(path.length);
24 for (let letter of KEYBOARD[next_number]) {
25 path.push(letter);
26 dfs(digits, path, res);
27 path.pop();
28 }
29}
30
Recommended Readings
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
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!