1816. Truncate Sentence
Problem Description
You are given a sentence s
which is a string of words separated by single spaces, with no leading or trailing spaces. Each word contains only uppercase and lowercase English letters with no punctuation marks.
Your task is to truncate the sentence so that it contains only the first k
words. You need to return the truncated sentence.
For example:
- If
s = "Hello World this is amazing"
andk = 3
, you should return"Hello World this"
(the first 3 words) - If
s = "What is the solution to this problem"
andk = 4
, you should return"What is the solution to"
(the first 4 words)
The solution approach splits the sentence into individual words using the split()
method, takes the first k
words using slice notation [:k]
, and then joins them back together with spaces using ' '.join()
. This creates the truncated sentence containing exactly k
words.
An alternative approach would be to iterate through the string character by character, counting spaces to track the number of words encountered. When you've found k-1
spaces (which means you've passed k
words), you can return the substring up to that point. If the entire string is traversed without finding k
words, the original string is returned.
Intuition
When we need to extract the first k
words from a sentence, the most natural approach is to think about how words are structured in the sentence - they're separated by spaces. This immediately suggests two possible strategies:
The first thought is to leverage Python's built-in string manipulation capabilities. Since words are space-separated, we can use split()
to break the sentence into a list of individual words. Once we have this list, getting the first k
words is straightforward - we just slice the list with [:k]
. Finally, we need to reconstruct the sentence by joining these words back with spaces.
The second approach comes from thinking about the problem more directly - if we want the first k
words, we essentially need to find where the k
-th word ends. Since words are separated by spaces, the k
-th word ends right before the k
-th space in the sentence. So we could traverse the string and count spaces. When we encounter the k
-th space, we know we've found the boundary and can return everything before that position.
The split-and-join approach (' '.join(s.split()[:k])
) is more elegant and concise because it directly expresses what we want to do: "take the first k
words and put them back together." It also handles edge cases naturally - if there are fewer than k
words in the sentence, split()[:k]
will simply return all available words without any errors.
The space-counting approach, while more manual, can be slightly more efficient in terms of space complexity since it doesn't create an intermediate list of all words, but the difference is negligible for most practical purposes.
Solution Approach
The reference solution uses a simulation approach by traversing the string character by character and counting spaces to determine word boundaries.
Let's walk through the implementation:
-
Initialize traversal: Start iterating through the string
s
from index0
. -
Count words by spaces: For each character
s[i]
we encounter:- If the character is a space, it means we've just completed reading a word
- Decrement
k
by 1 since we've processed one word - When
k
reaches0
, we've found exactlyk
words
-
Return the truncated string: When
k
becomes0
, return the substrings[0:i]
which contains all characters from the beginning up to (but not including) the current space character. This gives us exactly the firstk
words. -
Handle edge case: If we traverse the entire string without
k
reaching0
, it means the sentence has fewer thank
words. In this case, return the entire strings
.
The algorithm works because:
- Each space marks the end of a word (except there's no trailing space after the last word)
- By counting spaces, we effectively count completed words
- The position where we find the
k
-th space is exactly where we need to truncate
Time Complexity: O(n)
where n
is the length of the string, as we traverse the string once.
Space Complexity: O(1)
for the traversal approach (not counting the output string), or O(n)
for the split-and-join approach due to the intermediate list creation.
The provided solution code uses a more Pythonic approach with ' '.join(s.split()[:k])
:
s.split()
breaks the sentence into a list of words[:k]
slices the firstk
words from the list' '.join()
concatenates them back with spaces between words
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 the example s = "Hello World this is amazing"
and k = 3
.
Using the split-and-join approach:
-
Start with the sentence:
"Hello World this is amazing"
-
Apply
s.split()
to break it into words:- Result:
["Hello", "World", "this", "is", "amazing"]
- Result:
-
Take the first
k = 3
words using slice notation[:3]
:- Result:
["Hello", "World", "this"]
- Result:
-
Join these words back together with spaces using
' '.join()
:- Result:
"Hello World this"
- Result:
Using the space-counting approach:
-
Start traversing the string from index 0, with
k = 3
-
Iterate through each character:
- Index 0-4: "Hello" - no space yet
- Index 5: Found first space →
k = 2
(one word completed) - Index 6-10: "World" - continue
- Index 11: Found second space →
k = 1
(two words completed) - Index 12-15: "this" - continue
- Index 16: Found third space →
k = 0
(three words completed)
-
When
k
reaches 0 at index 16, returns[0:16]
- Result:
"Hello World this"
- Result:
Both approaches yield the same result. The first approach is more direct and Pythonic, while the second approach shows the underlying logic of identifying word boundaries through space counting.
Solution Implementation
1class Solution:
2 def truncateSentence(self, s: str, k: int) -> str:
3 """
4 Truncates a sentence to contain only the first k words.
5
6 Args:
7 s: Input sentence as a string with words separated by spaces
8 k: Number of words to keep from the beginning of the sentence
9
10 Returns:
11 A string containing only the first k words from the original sentence
12 """
13 # Split the sentence into a list of words using whitespace as delimiter
14 words = s.split()
15
16 # Take only the first k words from the list
17 first_k_words = words[:k]
18
19 # Join the selected words back into a string with spaces
20 truncated_sentence = ' '.join(first_k_words)
21
22 return truncated_sentence
23
1class Solution {
2 /**
3 * Truncates a sentence to contain only the first k words.
4 *
5 * @param s The input sentence with words separated by single spaces
6 * @param k The number of words to keep
7 * @return A string containing the first k words from the sentence
8 */
9 public String truncateSentence(String s, int k) {
10 // Iterate through each character in the string
11 for (int i = 0; i < s.length(); i++) {
12 // Check if current character is a space (word separator)
13 if (s.charAt(i) == ' ') {
14 // Decrement k and check if we've found k words
15 k--;
16 if (k == 0) {
17 // Return substring from start to current position (excluding the space)
18 return s.substring(0, i);
19 }
20 }
21 }
22
23 // If we've gone through the entire string without finding k spaces,
24 // it means the sentence has exactly k words or fewer, so return the entire string
25 return s;
26 }
27}
28
1class Solution {
2public:
3 string truncateSentence(string s, int k) {
4 // Iterate through each character in the string
5 for (int i = 0; i < s.size(); ++i) {
6 // Check if current character is a space
7 if (s[i] == ' ') {
8 // Decrement k and check if we've found k words
9 k--;
10 if (k == 0) {
11 // Return substring from start to current position (excluding the space)
12 return s.substr(0, i);
13 }
14 }
15 }
16 // If we've processed the entire string without finding k spaces,
17 // it means the sentence has k or fewer words, so return the entire string
18 return s;
19 }
20};
21
1/**
2 * Truncates a sentence to contain only the first k words.
3 * Words are separated by single spaces.
4 *
5 * @param s - The input sentence string
6 * @param k - The number of words to keep
7 * @returns The truncated sentence containing the first k words
8 */
9function truncateSentence(s: string, k: number): string {
10 // Iterate through each character in the string
11 for (let i = 0; i < s.length; i++) {
12 // Check if current character is a space
13 if (s[i] === ' ') {
14 // Decrement k and check if we've found k words
15 k--;
16 if (k === 0) {
17 // Return substring from start to current position (excluding the space)
18 return s.slice(0, i);
19 }
20 }
21 }
22
23 // If we've gone through the entire string without finding k spaces,
24 // it means the sentence has k or fewer words, so return the entire string
25 return s;
26}
27
Time and Space Complexity
Time Complexity: O(n)
, where n
is the length of the string s
. The split()
method needs to traverse the entire string to identify all word boundaries, which takes O(n)
time. The slicing operation [:k]
takes O(k)
time, and the join()
operation takes O(m)
time where m
is the total length of the first k
words. Since m ≤ n
, the overall time complexity is dominated by O(n)
.
Space Complexity: O(n)
. The split()
method creates a new list containing all words from the string, which in the worst case (when the string contains no spaces) could require O(n)
space. Additionally, the slicing [:k]
creates another list of size k
, and the join()
creates the output string. If we exclude the space required for the output (as mentioned in the reference), we still have O(n)
space complexity due to the intermediate list created by split()
.
Note: The reference answer states space complexity as O(1)
when ignoring the output space, but this appears to be incorrect for this implementation. The split()
method creates an intermediate list that requires O(n)
auxiliary space.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Assuming Multiple Spaces Between Words
A common mistake is thinking the input might have multiple consecutive spaces between words, leading to unnecessary complexity in the solution.
Pitfall Example:
# Overcomplicated approach trying to handle multiple spaces
def truncateSentence(self, s: str, k: int) -> str:
words = []
current_word = ""
for char in s:
if char == ' ':
if current_word: # Only add non-empty words
words.append(current_word)
current_word = ""
else:
current_word += char
# Don't forget the last word!
if current_word:
words.append(current_word)
return ' '.join(words[:k])
Solution: The problem guarantees single spaces between words with no leading or trailing spaces. Simply use s.split()
which handles this perfectly.
2. Off-by-One Error in Manual Traversal
When implementing the character-by-character traversal approach, it's easy to miscount spaces or words.
Pitfall Example:
def truncateSentence(self, s: str, k: int) -> str:
if k == 0:
return ""
space_count = 0
for i in range(len(s)):
if s[i] == ' ':
space_count += 1
if space_count == k: # Wrong! This finds k spaces, not k words
return s[:i]
return s
Solution: Remember that k
words means finding k-1
spaces (since there's no space after the last word). The correct condition should be if space_count == k - 1
or decrement k when finding spaces and check if k == 1
.
3. Forgetting Edge Cases
Not handling cases where the sentence has fewer words than k.
Pitfall Example:
def truncateSentence(self, s: str, k: int) -> str:
words = s.split()
return ' '.join(words[:k]) # This actually works, but some might try...
# Incorrect attempt at "optimization"
if len(words) < k:
raise ValueError("Not enough words") # Wrong! Should return entire string
Solution: Python's list slicing words[:k]
automatically handles this case correctly - if k is larger than the list length, it returns the entire list. No special handling needed.
4. Inefficient String Concatenation
Building the result character by character in a loop can be inefficient.
Pitfall Example:
def truncateSentence(self, s: str, k: int) -> str:
result = ""
word_count = 0
current_word = ""
for char in s:
if char == ' ':
if word_count < k:
if result:
result += " " + current_word # String concatenation in loop
else:
result = current_word
word_count += 1
current_word = ""
else:
current_word += char # More string concatenation
# Handle last word
if word_count < k and current_word:
if result:
result += " " + current_word
else:
result = current_word
return result
Solution: Use split()
and join()
for cleaner, more efficient code. If manual traversal is needed, find the truncation index and use string slicing s[:index]
instead of building character by character.
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
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!