1859. Sorting the Sentence
Problem Description
You are given a sentence that has been shuffled in a special way. Originally, the sentence was a normal list of words separated by single spaces with no leading or trailing spaces. Each word contains only lowercase and uppercase English letters.
The shuffling process works like this: each word gets a number (1, 2, 3, etc.) appended to its end based on its position in the original sentence (1 for the first word, 2 for the second word, and so on). Then, all these modified words are rearranged randomly.
For example:
- Original sentence:
"This is a sentence"
- After adding position numbers:
"This1 is2 a3 sentence4"
- After shuffling:
"sentence4 a3 is2 This1"
or"is2 sentence4 This1 a3"
or any other arrangement
Your task is to take a shuffled sentence s
(containing no more than 9 words) and reconstruct the original sentence by:
- Identifying the position number at the end of each word
- Placing each word back in its correct position (without the number)
- Returning the reconstructed sentence as a string
The solution approach splits the shuffled sentence into words, extracts the position number from the last character of each word, removes that number from the word, and places the word at its correct position in the result array. The position number at the end of each word tells us exactly where that word should go in the original sentence (remembering that positions are 1-indexed, so we need to subtract 1 for array indexing). Finally, all words are joined back together with spaces to form the original sentence.
Intuition
Since each word in the shuffled sentence has its original position number attached at the end, we have all the information needed to reconstruct the original sentence. The key insight is that the number at the end of each word acts like a label telling us exactly where that word belongs.
Think of it like having a jigsaw puzzle where each piece has a number written on it telling you its exact position. You don't need to figure out which piece goes where through trial and error - you just look at the number and place it accordingly.
The process becomes straightforward:
- We know each word ends with a digit (1-9) that represents its position
- We can extract this digit to know where to place the word
- We can remove this digit to get the original word back
For example, when we see "sentence4"
, we immediately know:
- The word is
"sentence"
(everything except the last character) - It belongs at position 4 in the original sentence
- Since arrays are 0-indexed, we place it at index 3 (
4 - 1
)
By creating an array with the same number of slots as we have words, we can directly place each word into its correct position as we process them. This eliminates the need for sorting - we're essentially doing a direct placement based on the embedded position information.
The beauty of this approach is its simplicity: we're not actually sorting anything despite the problem appearing to be about reordering. We're just reading the instructions that are already embedded in each word and following them directly.
Learn more about Sorting patterns.
Solution Approach
The implementation follows a direct placement strategy using an array to reconstruct the original sentence:
Step 1: Split the shuffled sentence
ws = s.split()
We split the input string s
by spaces to get an array of shuffled words. For example, "sentence4 a3 is2 This1"
becomes ["sentence4", "a3", "is2", "This1"]
.
Step 2: Initialize a result array
ans = [None] * len(ws)
We create an array ans
with the same length as the number of words. This array will hold the words in their correct positions. Using None
as placeholders ensures we have the right number of slots.
Step 3: Process each word and place it correctly
for w in ws:
ans[int(w[-1]) - 1] = w[:-1]
For each word w
in our shuffled words array:
w[-1]
extracts the last character (the position digit)int(w[-1])
converts this character to an integerint(w[-1]) - 1
adjusts from 1-indexed to 0-indexed for array placementw[:-1]
extracts everything except the last character (the original word)- We place the original word at its correct position in the
ans
array
For example, processing "sentence4"
:
w[-1]
gives us'4'
int('4') - 1 = 3
(the array index)w[:-1]
gives us"sentence"
- We place
"sentence"
atans[3]
Step 4: Join the words back together
return " ".join(ans)
Finally, we join all the words in the ans
array with spaces to create the reconstructed original sentence.
The time complexity is O(n)
where n
is the length of the input string, as we process each word once. The space complexity is also O(n)
for storing the split words and the result array.
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 concrete example with the shuffled sentence: "is2 sentence4 This1 a3"
Initial State:
- Input:
"is2 sentence4 This1 a3"
- We need to reconstruct:
"This is a sentence"
Step 1: Split the sentence
ws = ["is2", "sentence4", "This1", "a3"]
Step 2: Create result array
ans = [None, None, None, None] # 4 slots for 4 words
Step 3: Process each word
Processing "is2"
:
- Last character:
'2'
β position 2 - Array index:
2 - 1 = 1
- Word without number:
"is"
- Place at index 1:
ans = [None, "is", None, None]
Processing "sentence4"
:
- Last character:
'4'
β position 4 - Array index:
4 - 1 = 3
- Word without number:
"sentence"
- Place at index 3:
ans = [None, "is", None, "sentence"]
Processing "This1"
:
- Last character:
'1'
β position 1 - Array index:
1 - 1 = 0
- Word without number:
"This"
- Place at index 0:
ans = ["This", "is", None, "sentence"]
Processing "a3"
:
- Last character:
'3'
β position 3 - Array index:
3 - 1 = 2
- Word without number:
"a"
- Place at index 2:
ans = ["This", "is", "a", "sentence"]
Step 4: Join with spaces
Result: "This is a sentence"
Each word finds its home directly based on the number attached to it - no sorting needed, just direct placement into the correct position.
Solution Implementation
1class Solution:
2 def sortSentence(self, s: str) -> str:
3 """
4 Reconstructs a sentence by sorting words based on their trailing position numbers.
5
6 Args:
7 s: A shuffled sentence where each word ends with its position number (1-indexed)
8
9 Returns:
10 The original sentence with words in correct order and position numbers removed
11 """
12 # Split the sentence into individual words
13 words = s.split()
14
15 # Initialize result array with size equal to number of words
16 result = [None] * len(words)
17
18 # Process each word
19 for word in words:
20 # Extract position from last character (convert to 0-indexed)
21 position = int(word[-1]) - 1
22
23 # Place word (without position number) at correct index
24 result[position] = word[:-1]
25
26 # Join words back into a sentence
27 return " ".join(result)
28
1class Solution {
2 public String sortSentence(String s) {
3 // Split the sentence into individual words
4 String[] words = s.split(" ");
5 int wordCount = words.length;
6
7 // Create an array to store words in their correct positions
8 String[] sortedWords = new String[wordCount];
9
10 // Process each word to extract its position and content
11 for (int i = 0; i < wordCount; ++i) {
12 String currentWord = words[i];
13
14 // Get the last character (position digit) and convert to index (0-based)
15 int position = currentWord.charAt(currentWord.length() - 1) - '1';
16
17 // Extract the word without the position digit and place it at correct index
18 sortedWords[position] = currentWord.substring(0, currentWord.length() - 1);
19 }
20
21 // Join the sorted words back into a sentence with spaces
22 return String.join(" ", sortedWords);
23 }
24}
25
1class Solution {
2public:
3 string sortSentence(string s) {
4 // Create input string stream to parse words from the sentence
5 istringstream inputStream(s);
6 string word;
7 vector<string> words;
8
9 // Extract all words from the sentence (each word has a digit at the end)
10 while (inputStream >> word) {
11 words.push_back(word);
12 }
13
14 // Create result vector with the same size as number of words
15 vector<string> sortedWords(words.size());
16
17 // Place each word in its correct position based on the digit at the end
18 for (const auto& currentWord : words) {
19 // Extract position from last character (digit) and convert to 0-based index
20 int position = currentWord.back() - '1';
21
22 // Remove the digit from the word and place it in correct position
23 sortedWords[position] = currentWord.substr(0, currentWord.size() - 1);
24 }
25
26 // Build the result string by concatenating sorted words with spaces
27 string result;
28 for (const auto& word : sortedWords) {
29 result += word + " ";
30 }
31
32 // Remove the trailing space
33 result.pop_back();
34
35 return result;
36 }
37};
38
1/**
2 * Sorts words in a sentence based on the numeric suffix of each word
3 * @param s - Input string with words ending in position numbers (1-9)
4 * @returns The sentence with words sorted by their position numbers
5 */
6function sortSentence(s: string): string {
7 // Split the input string into individual words
8 const words: string[] = s.split(' ');
9
10 // Initialize result array with the same length as words array
11 const sortedWords: string[] = new Array(words.length);
12
13 // Process each word in the input
14 for (const word of words) {
15 // Extract the position index from the last character (convert from 1-based to 0-based)
16 // charCodeAt gets ASCII value, subtracting '1' ASCII value gives numeric position
17 const positionIndex: number = word.charCodeAt(word.length - 1) - '1'.charCodeAt(0);
18
19 // Remove the last character (number) from the word and place it at correct position
20 sortedWords[positionIndex] = word.slice(0, -1);
21 }
22
23 // Join the sorted words back into a sentence with spaces
24 return sortedWords.join(' ');
25}
26
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the string s
. This is because:
- Splitting the string takes
O(n)
time to traverse through all characters - The for loop iterates through each word once, and each word's operations (accessing last character, slicing, and assignment) are
O(1)
on average - Joining the result array back into a string requires
O(n)
time to concatenate all characters
The space complexity is O(n)
, where n
is the length of the string s
. This is because:
- The
ws
list stores all words from the split operation, which collectively contain all characters froms
, requiringO(n)
space - The
ans
list stores the reordered words (without their position digits), which is alsoO(n)
space - The final joined string is
O(n)
space
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Assuming Words Can Have Multi-Digit Position Numbers
A common mistake is overthinking the problem and trying to handle position numbers with multiple digits (like "word10" or "word123"). This leads to unnecessarily complex parsing logic.
Incorrect approach:
# Trying to extract multi-digit numbers from the end
import re
def sortSentence(self, s: str) -> str:
words = s.split()
result = [None] * len(words)
for word in words:
# Overly complex regex to find trailing digits
match = re.search(r'(\d+)$', word)
if match:
position = int(match.group(1))
clean_word = word[:match.start()]
result[position - 1] = clean_word
return " ".join(result)
Why this is a pitfall: The problem explicitly states the sentence contains "no more than 9 words," meaning position numbers are always single digits (1-9). The simple word[-1]
approach is sufficient and more efficient.
2. Forgetting to Convert from 1-Indexed to 0-Indexed
Another frequent error is directly using the position number as an array index without adjusting for 0-based indexing.
Incorrect approach:
def sortSentence(self, s: str) -> str:
words = s.split()
result = [None] * len(words)
for word in words:
position = int(word[-1]) # This is 1-indexed
result[position] = word[:-1] # ERROR: array index out of bounds
return " ".join(result)
Why this fails: If we have 4 words with positions 1-4, trying to access result[4]
will cause an IndexError since valid indices are 0-3.
Correct approach: Always subtract 1 from the position number: result[int(word[-1]) - 1] = word[:-1]
3. Not Handling Edge Cases with Word Content
Some might worry about words that naturally end with digits (though the problem doesn't include such cases).
Overthinking example:
def sortSentence(self, s: str) -> str:
words = s.split()
result = [None] * len(words)
for word in words:
# Trying to validate if the last character is "really" a position
if word[-1].isdigit() and 1 <= int(word[-1]) <= 9:
position = int(word[-1]) - 1
result[position] = word[:-1]
else:
# Unnecessary error handling
raise ValueError("Invalid word format")
return " ".join(result)
Why this is unnecessary: The problem guarantees that each word has exactly one position digit at the end. Adding validation for cases that won't occur adds complexity without value.
Best practice: Trust the problem constraints and keep the solution simple and direct.
What's the output of running the following function using the following tree as input?
1def serialize(root):
2 res = []
3 def dfs(root):
4 if not root:
5 res.append('x')
6 return
7 res.append(root.val)
8 dfs(root.left)
9 dfs(root.right)
10 dfs(root)
11 return ' '.join(res)
12
1import java.util.StringJoiner;
2
3public static String serialize(Node root) {
4 StringJoiner res = new StringJoiner(" ");
5 serializeDFS(root, res);
6 return res.toString();
7}
8
9private static void serializeDFS(Node root, StringJoiner result) {
10 if (root == null) {
11 result.add("x");
12 return;
13 }
14 result.add(Integer.toString(root.val));
15 serializeDFS(root.left, result);
16 serializeDFS(root.right, result);
17}
18
1function serialize(root) {
2 let res = [];
3 serialize_dfs(root, res);
4 return res.join(" ");
5}
6
7function serialize_dfs(root, res) {
8 if (!root) {
9 res.push("x");
10 return;
11 }
12 res.push(root.val);
13 serialize_dfs(root.left, res);
14 serialize_dfs(root.right, res);
15}
16
Recommended Readings
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
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!