2042. Check if Numbers Are Ascending in a Sentence
Problem Description
You are given a string s
that represents a sentence. A sentence consists of tokens separated by single spaces, with no leading or trailing spaces. Each token is either:
- A positive number made up of digits 0-9 with no leading zeros
- A word made up of lowercase English letters
For example, "a puppy has 2 eyes 4 legs"
contains 7 tokens where "2"
and "4"
are numbers, while "a"
, "puppy"
, "has"
, "eyes"
, and "legs"
are words.
Your task is to check if all the numbers in the sentence appear in strictly increasing order from left to right. This means each number must be strictly smaller than the next number that appears after it in the sentence.
Return true
if all numbers are in strictly increasing order, or false
otherwise.
The solution works by:
- Splitting the string
s
into individual tokens using spaces - For each token, checking if it starts with a digit (indicating it's a number)
- If it's a number, converting it to an integer and comparing with the previous number
- If any number is not greater than the previous one, returning
false
- If all numbers maintain strict increasing order, returning
true
The key insight is using the isdigit()
method to identify numbers and maintaining a pre
variable to track the previous number for comparison. The walrus operator :=
is used to assign and use the current number value in a single expression.
Intuition
The problem asks us to verify if numbers in a sentence follow a strictly increasing pattern. The natural approach is to process the sentence sequentially from left to right, just as we would read it.
Since we need to compare consecutive numbers, we need to:
- Extract all numbers from the sentence in the order they appear
- Compare each number with the one before it
The key observation is that we don't need to store all numbers - we only need to remember the last number we encountered to compare with the current one. This is because "strictly increasing" means each number only needs to be greater than the immediate previous number.
To identify whether a token is a number or a word, we can check if its first character is a digit. Since the problem guarantees that numbers have no leading zeros (except for the number 0 itself), checking token[0].isdigit()
is sufficient to determine if a token is a number.
The algorithm naturally follows a single-pass pattern:
- Initialize a variable
pre
to track the previous number (starting at 0 since all numbers are positive) - Split the sentence into tokens
- For each token that's a number, check if it's greater than
pre
- If we find any number that's not greater than the previous one, we can immediately return
false
- Update
pre
to the current number and continue - If we process all numbers without finding a violation, return
true
This greedy approach works because the strictly increasing property is transitive - if a < b
and b < c
, then a < c
. So we only need to check adjacent pairs of numbers in sequence.
Solution Approach
The implementation follows a straightforward simulation approach by processing the sentence token by token.
Step-by-step implementation:
-
Initialize tracking variable: Start with
pre = 0
to keep track of the previous number. We use 0 as the initial value since all numbers in the sentence are positive integers, ensuring the first number will always be greater thanpre
. -
Split the sentence into tokens: Use
s.split()
to break the sentence into individual tokens separated by spaces. This handles multiple spaces automatically and returns a list of non-empty tokens. -
Process each token: Iterate through each token
t
in the split sentence:- Check if the token is a number by testing if its first character is a digit:
t[0].isdigit()
- If it's a number:
- Convert it to an integer:
int(t)
- Compare with the previous number
- If the current number is less than or equal to the previous (
cur <= pre
), returnFalse
immediately - Otherwise, update
pre
to the current number for the next comparison
- Convert it to an integer:
- Check if the token is a number by testing if its first character is a digit:
-
Return result: If we complete the iteration without finding any violations, return
True
.
Key implementation details:
- The walrus operator
:=
is used to assign and use the converted integer value in one expression:if (cur := int(t)) <= pre:
- Early termination: As soon as we find a number that's not strictly greater than the previous one, we return
False
without checking remaining tokens - We only track numbers and completely ignore word tokens, as they don't affect the strictly increasing property
Time Complexity: O(n)
where n
is the length of the string, as we process each character once during splitting and iteration.
Space Complexity: O(m)
where m
is the number of tokens, needed to store the split result.
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: "hello world 5 x 9 y 27"
Initial State:
pre = 0
(tracks the previous number)- Split the string:
["hello", "world", "5", "x", "9", "y", "27"]
Processing each token:
-
Token: "hello"
- Check:
"hello"[0].isdigit()
→"h".isdigit()
→False
- This is a word, skip it
pre
remains0
- Check:
-
Token: "world"
- Check:
"world"[0].isdigit()
→"w".isdigit()
→False
- This is a word, skip it
pre
remains0
- Check:
-
Token: "5"
- Check:
"5"[0].isdigit()
→True
- This is a number!
- Convert:
cur = int("5") = 5
- Compare: Is
5 <= 0
? →False
(5 > 0, so it's good) - Update:
pre = 5
- Check:
-
Token: "x"
- Check:
"x"[0].isdigit()
→False
- This is a word, skip it
pre
remains5
- Check:
-
Token: "9"
- Check:
"9"[0].isdigit()
→True
- This is a number!
- Convert:
cur = int("9") = 9
- Compare: Is
9 <= 5
? →False
(9 > 5, so it's good) - Update:
pre = 9
- Check:
-
Token: "y"
- Check:
"y"[0].isdigit()
→False
- This is a word, skip it
pre
remains9
- Check:
-
Token: "27"
- Check:
"27"[0].isdigit()
→"2".isdigit()
→True
- This is a number!
- Convert:
cur = int("27") = 27
- Compare: Is
27 <= 9
? →False
(27 > 9, so it's good) - Update:
pre = 27
- Check:
Result: All numbers (5, 9, 27) are in strictly increasing order, so return True
.
Counter-example: If the sentence was "hello 5 x 3 y 27"
, the algorithm would:
- Process "5":
pre = 5
- Process "3": Compare
3 <= 5
? →True
(violation!) - Immediately return
False
without checking "27"
Solution Implementation
1class Solution:
2 def areNumbersAscending(self, s: str) -> bool:
3 """
4 Check if all numbers in the string appear in strictly ascending order.
5
6 Args:
7 s: Input string containing words and numbers separated by spaces
8
9 Returns:
10 True if numbers are in strictly ascending order, False otherwise
11 """
12 # Initialize previous number to track ascending order
13 previous_number = 0
14
15 # Split the string into tokens by whitespace
16 tokens = s.split()
17
18 # Iterate through each token
19 for token in tokens:
20 # Check if the token is a number (starts with a digit)
21 if token[0].isdigit():
22 # Convert token to integer
23 current_number = int(token)
24
25 # Check if current number is not strictly greater than previous
26 if current_number <= previous_number:
27 return False
28
29 # Update previous number for next comparison
30 previous_number = current_number
31
32 # All numbers are in strictly ascending order
33 return True
34
1class Solution {
2 /**
3 * Checks if all numbers in a string are in strictly ascending order.
4 *
5 * @param s the input string containing words and numbers separated by spaces
6 * @return true if all numbers are in strictly ascending order, false otherwise
7 */
8 public boolean areNumbersAscending(String s) {
9 // Track the previous number to compare with current number
10 int previousNumber = 0;
11
12 // Split the string by spaces and iterate through each token
13 for (String token : s.split(" ")) {
14 // Check if the token is a number by examining if first character is a digit
15 if (token.charAt(0) >= '0' && token.charAt(0) <= '9') {
16 // Parse the current token as an integer
17 int currentNumber = Integer.parseInt(token);
18
19 // Check if numbers are in strictly ascending order
20 if (previousNumber >= currentNumber) {
21 return false;
22 }
23
24 // Update previous number for next comparison
25 previousNumber = currentNumber;
26 }
27 }
28
29 // All numbers are in strictly ascending order
30 return true;
31 }
32}
33
1class Solution {
2public:
3 bool areNumbersAscending(string s) {
4 int previousNumber = 0; // Track the previous number for comparison
5 istringstream inputStream(s); // Create a string stream to parse words
6 string word;
7
8 // Read each word from the string stream
9 while (inputStream >> word) {
10 // Check if the current word is a number (starts with a digit)
11 if (isdigit(word[0])) {
12 int currentNumber = stoi(word); // Convert string to integer
13
14 // Check if numbers are in strictly ascending order
15 if (previousNumber >= currentNumber) {
16 return false; // Not strictly ascending
17 }
18
19 previousNumber = currentNumber; // Update previous number
20 }
21 }
22
23 return true; // All numbers are in strictly ascending order
24 }
25};
26
1/**
2 * Checks if all numbers in a string are in strictly ascending order
3 * @param s - Input string containing words and numbers separated by spaces
4 * @returns true if all numbers are in strictly ascending order, false otherwise
5 */
6function areNumbersAscending(s: string): boolean {
7 // Initialize previous number to track ascending order
8 let previousNumber: number = -1;
9
10 // Split the string by spaces and iterate through each token
11 for (const token of s.split(' ')) {
12 // Check if the token starts with a digit (0-9)
13 if (token[0] >= '0' && token[0] <= '9') {
14 // Convert the token to a number
15 const currentNumber: number = Number(token);
16
17 // Check if current number is not greater than previous number
18 if (currentNumber <= previousNumber) {
19 return false;
20 }
21
22 // Update previous number for next comparison
23 previousNumber = currentNumber;
24 }
25 }
26
27 // All numbers are in strictly ascending order
28 return true;
29}
30
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the string s
. This is because:
- The
s.split()
operation needs to traverse the entire string once to identify word boundaries, which takesO(n)
time - The iteration through the split tokens also takes
O(n)
time in the worst case (when processing all characters) - For each token that is a number,
int(t)
conversion takesO(k)
time wherek
is the length of the number, but since all number lengths sum up to at mostn
, the total conversion time is stillO(n)
The space complexity is O(n)
, where n
is the length of the string s
. This is because:
- The
s.split()
method creates a new list containing all the tokens from the string, which in the worst case could beO(n)
space (e.g., when the string is "1 2 3 4 5...") - The individual tokens themselves also consume space proportional to the original string length
- The variables
pre
andcur
only useO(1)
additional space
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Assuming tokens are always single characters
A common mistake is checking only token[0].isdigit()
without considering that the entire token should be validated as a number. While this works for the given problem constraints (numbers have no leading zeros), it could fail if the problem allowed mixed tokens like "2abc" or if you need to handle edge cases.
Pitfall Example:
# This would incorrectly identify "2abc" as a number
if token[0].isdigit():
current_number = int(token) # Would crash with ValueError
Solution:
Use token.isdigit()
to check if the entire token consists of digits:
if token.isdigit():
current_number = int(token)
2. Not handling empty strings or edge cases
The code assumes the input is well-formed, but doesn't explicitly handle empty strings or tokens.
Pitfall Example:
# Would crash on empty string s = "" tokens = s.split() # Returns [] for token in tokens: if token[0].isdigit(): # No issue here since loop doesn't execute
Solution: Add validation for empty or malformed tokens:
for token in tokens:
if token and token[0].isdigit(): # Check token is not empty
current_number = int(token)
3. Using wrong initial value for previous_number
Setting previous_number
to a non-zero value could cause incorrect results.
Pitfall Example:
previous_number = 10 # Wrong initial value # String "5 is less than 10" would incorrectly return False
Solution: Always initialize to 0 or negative infinity for positive numbers:
previous_number = 0 # Correct for positive numbers
# or
previous_number = float('-inf') # Works for any numbers
4. Confusing strictly increasing with non-decreasing
The problem requires strictly increasing order (each number must be greater than the previous), not just non-decreasing (greater than or equal).
Pitfall Example:
# Wrong: allows equal numbers if current_number < previous_number: # Should be <= return False
Solution:
Use <=
to ensure strict inequality:
if current_number <= previous_number: # Correct return False
Which algorithm should you use to find a node that is close to the root of the tree?
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!