Facebook Pixel

1592. Rearrange Spaces Between Words

EasyString
Leetcode Link

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:

  1. The spaces between adjacent words are distributed as equally as possible
  2. The number of spaces between each pair of adjacent words should be maximized and equal
  3. 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
  4. 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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. 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.

  2. 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"].

  3. 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.

  4. Calculate space distribution: For multiple words, we need to distribute spaces among len(words) - 1 gaps. We use divmod(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)
  5. Reconstruct the string: We use two operations:

    • (" " * cnt).join(words): Creates a string with cnt spaces between each word. The join method inserts the separator (which is cnt spaces) between each element in the words 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) returns cnt = 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 Evaluator

Example 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 most O(n) since mod < 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 most n 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 by O(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.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More